@biffo/cli 0.142.1 → 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.
@@ -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
- - uses: gitleaks/gitleaks-action@v2
112
- env:
113
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
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
@@ -45,7 +45,7 @@ env:
45
45
  jobs:
46
46
  release:
47
47
  name: Build, Version & Publish
48
- runs-on: ubuntu-latest
48
+ runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
49
49
  environment:
50
50
  name: pypi
51
51
  url: https://pypi.org/project/biffo-plugin-example/
@@ -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. Security
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", "ANN"]
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. ANN: test functions don't need
63
- # return-type annotations. S106: fakes.py's mock BiffoAPIClient(token=...)
64
- # is a fixed test fixture value, not a real credential.
65
- "tests/**/*.py" = ["S101", "ANN", "S106"]
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 the test-local `fakes` module importable.
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 `import fakes` as a plain sibling module (pytest's rootdir insertion
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
@@ -9,7 +9,7 @@ monorepo.
9
9
  from __future__ import annotations
10
10
 
11
11
  from biffo_plugin_sdk import BiffoEvent
12
- from fakes import FakeCoreApi
12
+ from example_plugin_fakes import FakeCoreApi
13
13
 
14
14
  from example_plugin.plugin import _DEFAULT_WIDGET, ExamplePlugin
15
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biffo/cli",
3
- "version": "0.142.1",
3
+ "version": "0.142.2",
4
4
  "description": "Biffo project scaffolding CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
File without changes