@biffo/cli 0.142.0 → 0.142.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_skeletons/plugin-template/.github/workflows/ci.yml +36 -9
- package/_skeletons/plugin-template/.github/workflows/release.yml +1 -1
- package/_skeletons/plugin-template/AGENTS.md +18 -1
- package/_skeletons/plugin-template/pyproject.toml +31 -5
- package/_skeletons/plugin-template/tests/conftest.py +10 -2
- package/_skeletons/plugin-template/tests/test_example_plugin.py +1 -1
- package/package.json +1 -1
- package/_skeletons/plugin-template/src/__init__.py +0 -0
- /package/_skeletons/plugin-template/tests/{fakes.py → example_plugin_fakes.py} +0 -0
|
@@ -22,7 +22,7 @@ env:
|
|
|
22
22
|
jobs:
|
|
23
23
|
lint:
|
|
24
24
|
name: Lint
|
|
25
|
-
runs-on: ubuntu-latest
|
|
25
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
26
26
|
steps:
|
|
27
27
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
28
28
|
- uses: astral-sh/setup-uv@v5
|
|
@@ -34,7 +34,7 @@ jobs:
|
|
|
34
34
|
|
|
35
35
|
typecheck:
|
|
36
36
|
name: Type Check
|
|
37
|
-
runs-on: ubuntu-latest
|
|
37
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
38
38
|
steps:
|
|
39
39
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
40
40
|
- uses: astral-sh/setup-uv@v5
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
|
|
46
46
|
test:
|
|
47
47
|
name: Test
|
|
48
|
-
runs-on: ubuntu-latest
|
|
48
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
49
49
|
steps:
|
|
50
50
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
51
51
|
- uses: astral-sh/setup-uv@v5
|
|
@@ -60,7 +60,7 @@ jobs:
|
|
|
60
60
|
|
|
61
61
|
validate-manifest:
|
|
62
62
|
name: Validate biffo.plugin.json
|
|
63
|
-
runs-on: ubuntu-latest
|
|
63
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
64
64
|
steps:
|
|
65
65
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
66
66
|
- uses: astral-sh/setup-uv@v5
|
|
@@ -100,7 +100,7 @@ jobs:
|
|
|
100
100
|
|
|
101
101
|
security-secrets:
|
|
102
102
|
name: Secret Scan
|
|
103
|
-
runs-on: ubuntu-latest
|
|
103
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
104
104
|
permissions:
|
|
105
105
|
contents: read
|
|
106
106
|
pull-requests: read
|
|
@@ -108,13 +108,40 @@ jobs:
|
|
|
108
108
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
109
109
|
with:
|
|
110
110
|
fetch-depth: 0
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
# gitleaks/gitleaks-action@v2 cannot pass here, for two independent
|
|
112
|
+
# reasons, and a generated plugin repo would be born permanently red:
|
|
113
|
+
#
|
|
114
|
+
# 1. On self-hosted runners the scan succeeds and the action then dies
|
|
115
|
+
# uploading its SARIF — it assumes a GitHub-hosted $HOME layout, and
|
|
116
|
+
# on the AWS fleet the workspace is not under $HOME.
|
|
117
|
+
# 2. It requires a paid GITLEAKS_LICENSE for organization-owned repos
|
|
118
|
+
# (confirmed on tabsii-com/tabsii-platform and tabsii-com/tabsii-crm).
|
|
119
|
+
#
|
|
120
|
+
# Install the free, open-source CLI instead — the same approach this
|
|
121
|
+
# template's own root ci.yml uses. Keep the two in step (issue #649).
|
|
122
|
+
- name: Install gitleaks
|
|
123
|
+
run: |
|
|
124
|
+
curl -sSfL -o gitleaks.tar.gz https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz
|
|
125
|
+
echo "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb gitleaks.tar.gz" | sha256sum -c -
|
|
126
|
+
tar -xzf gitleaks.tar.gz -C /usr/local/bin gitleaks
|
|
127
|
+
gitleaks version
|
|
128
|
+
# --log-opts is load-bearing (issue #258). gitleaks defaults to `--all`,
|
|
129
|
+
# so with fetch-depth: 0 the scan reaches commits that exist only on
|
|
130
|
+
# unmerged branches — one bad commit on anyone's open branch then reddens
|
|
131
|
+
# every open PR, with nothing in the built ref responsible for it.
|
|
132
|
+
# Scoping to HEAD does not weaken detection: the full reachable history is
|
|
133
|
+
# still walked, so a secret committed then removed is still caught.
|
|
134
|
+
- name: gitleaks git history scan
|
|
135
|
+
run: gitleaks detect --redact -v --exit-code=2 --log-opts="--full-history HEAD"
|
|
136
|
+
# Second pass over the working tree. A generated repo's initial commit
|
|
137
|
+
# contains every skeleton file, so a secret in an unchanged file would
|
|
138
|
+
# pass the history scan and fail here. Running both closes the gap.
|
|
139
|
+
- name: gitleaks filesystem scan
|
|
140
|
+
run: gitleaks detect --no-git --redact -v --exit-code=2
|
|
114
141
|
|
|
115
142
|
security-deps:
|
|
116
143
|
name: Dependency Audit
|
|
117
|
-
runs-on: ubuntu-latest
|
|
144
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
118
145
|
steps:
|
|
119
146
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
120
147
|
- uses: astral-sh/setup-uv@v5
|
|
@@ -66,7 +66,24 @@ repo; only its product differs.
|
|
|
66
66
|
before merge: `git log origin/<branch> -1`. A green PR page is not proof your
|
|
67
67
|
latest local commit reached it.
|
|
68
68
|
|
|
69
|
-
## 7.
|
|
69
|
+
## 7. CI runners — two steps this repo cannot do for itself
|
|
70
|
+
|
|
71
|
+
The workflows use `runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}`, so they
|
|
72
|
+
work anywhere by default and route to a self-hosted fleet when one exists. Two
|
|
73
|
+
things must be done **outside** this repo before its first run can succeed on a
|
|
74
|
+
fleet:
|
|
75
|
+
|
|
76
|
+
1. **Set the repo variable `RUNNER_LABEL`** to the fleet's label.
|
|
77
|
+
2. **Grant the runner GitHub App access to this repo.** The scale-up webhook only
|
|
78
|
+
sees repos the App can see. Without the grant, jobs queue **indefinitely with
|
|
79
|
+
no error** — and nothing in the UI distinguishes that from a slow runner. The
|
|
80
|
+
first plugin repo to hit this sat queued for **1h 44m** before anyone noticed
|
|
81
|
+
(`keiranholloway/biffo-runners#2`).
|
|
82
|
+
|
|
83
|
+
If a job is queued and nothing is happening, check the grant before anything
|
|
84
|
+
else. It is the failure that looks exactly like patience.
|
|
85
|
+
|
|
86
|
+
## 8. Security
|
|
70
87
|
|
|
71
88
|
- **Never commit secrets** (keys, tokens, credentials, `.env` values).
|
|
72
89
|
- **Never silently disable a security gate.** If one must be loosened, do it in
|
|
@@ -52,17 +52,43 @@ packages = ["src/example_plugin"]
|
|
|
52
52
|
target-version = "py313"
|
|
53
53
|
line-length = 100
|
|
54
54
|
|
|
55
|
+
# Match the select an instance actually enforces once this plugin is vendored
|
|
56
|
+
# into services/<name>/ — the instance applies it with no third-party carve-out,
|
|
57
|
+
# so a skeleton that is *stricter* makes an author write annotations nobody asked
|
|
58
|
+
# for, and one that is looser lets a plugin pass its own CI and fail the tree it
|
|
59
|
+
# lands in. Keep in step with the template root and biffo-plugin-ideation
|
|
60
|
+
# (issue #650).
|
|
61
|
+
#
|
|
62
|
+
# ANN is deliberately absent for that reason. It is also actively wrong in one
|
|
63
|
+
# place: ANN401 rejects the `Any` in a Pydantic mode="before" validator, which
|
|
64
|
+
# is the one signature where `Any` is genuinely correct.
|
|
55
65
|
[tool.ruff.lint]
|
|
56
|
-
select = ["E", "F", "I", "N", "W", "B", "S", "UP"
|
|
66
|
+
select = ["E", "F", "I", "N", "W", "B", "S", "UP"]
|
|
57
67
|
ignore = [
|
|
58
68
|
"S101", # allow assert in tests
|
|
59
69
|
]
|
|
60
70
|
|
|
71
|
+
# FastAPI's dependency-injection defaults are the framework's idiomatic
|
|
72
|
+
# call-in-default pattern, not the B008 mutable-default bug. Without this a
|
|
73
|
+
# plugin cannot write `x = Depends(...)` — the mandatory idiom for any plugin
|
|
74
|
+
# exposing routes — and B008 reddens its CI on the first endpoint it adds.
|
|
75
|
+
[tool.ruff.lint.flake8-bugbear]
|
|
76
|
+
extend-immutable-calls = [
|
|
77
|
+
"fastapi.Depends",
|
|
78
|
+
"fastapi.Query",
|
|
79
|
+
"fastapi.Path",
|
|
80
|
+
"fastapi.Body",
|
|
81
|
+
"fastapi.Header",
|
|
82
|
+
"fastapi.Cookie",
|
|
83
|
+
"fastapi.Form",
|
|
84
|
+
"fastapi.File",
|
|
85
|
+
]
|
|
86
|
+
|
|
61
87
|
[tool.ruff.lint.per-file-ignores]
|
|
62
|
-
# S101: assert is the normal pytest idiom.
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
"tests/**/*.py" = ["S101", "
|
|
88
|
+
# S101: assert is the normal pytest idiom. S106: fakes.py's mock
|
|
89
|
+
# BiffoAPIClient(token=...) is a fixed test fixture value, not a real
|
|
90
|
+
# credential. (ANN is no longer selected, so it needs no per-file ignore.)
|
|
91
|
+
"tests/**/*.py" = ["S101", "S106"]
|
|
66
92
|
|
|
67
93
|
[tool.ruff.format]
|
|
68
94
|
quote-style = "double"
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
"""Make `example_plugin` and
|
|
1
|
+
"""Make `example_plugin` and its test-local fakes module importable.
|
|
2
2
|
|
|
3
3
|
This template is a standalone repo (not part of the biffo-template
|
|
4
4
|
monorepo's uv workspace — see README's "Standalone repo" note), so
|
|
5
5
|
`example_plugin` is installed normally via the project's own
|
|
6
6
|
[build-system]/hatchling config when `uv sync` runs. This conftest only
|
|
7
7
|
needs to put `tests/` itself on sys.path so `tests/test_example_plugin.py`
|
|
8
|
-
can
|
|
8
|
+
can import its fakes as a plain sibling module (pytest's rootdir insertion
|
|
9
9
|
already covers this in most configurations, but the explicit path insert
|
|
10
10
|
keeps this working from any cwd, matching the RBAC reference plugin's
|
|
11
11
|
`services/rbac/tests/conftest.py` pattern in the biffo-template monorepo).
|
|
12
|
+
|
|
13
|
+
The fakes module is named after the plugin (`example_plugin_fakes.py`, which
|
|
14
|
+
scaffolding rewrites per plugin) rather than a bare `fakes.py`. Without
|
|
15
|
+
`__init__.py` here, pytest's prepend import mode imports test modules by bare
|
|
16
|
+
basename, so two vendored plugins both shipping `fakes.py` would fight over the
|
|
17
|
+
top-level module name and one would silently import the other's — which is
|
|
18
|
+
exactly what happened when a second plugin was installed (issue #688). Guarded
|
|
19
|
+
by `cli/src/lib/plugin-skeleton-second-occupant.test.ts`.
|
|
12
20
|
"""
|
|
13
21
|
|
|
14
22
|
import sys
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|