@taraxvoid/voidflow 0.8.3 → 0.10.0

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/README.md CHANGED
@@ -43,11 +43,61 @@ jobs:
43
43
  runner: my-hosted-runner
44
44
  ```
45
45
 
46
+ ### Single-environment sites
47
+
48
+ Sites with one production environment and no `next`/`live` branches (`main`
49
+ deploys to prod, pull requests get previews) pass `single-environment: true`,
50
+ the same flag `resolve-env` and `branch-env-map` take:
51
+
52
+ ```yaml
53
+ on:
54
+ push:
55
+ branches: [main]
56
+ pull_request:
57
+ branches: [main]
58
+ types: [opened, synchronize, reopened, ready_for_review]
59
+ workflow_dispatch:
60
+
61
+ jobs:
62
+ validate:
63
+ uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@<sha> # <version>
64
+ with:
65
+ single-environment: true
66
+ ```
67
+
68
+ `main` then gets the production test tier (`test:e2e:all`, `test:e2e:a11y`,
69
+ `test:e2e:lighthouse`) instead of only `test:e2e:full`. Include the `push`
70
+ trigger so a direct push to `main` is validated too; the e2e steps resolve the
71
+ branch from the pushed ref.
72
+
73
+ ### pnpm sites, build env, extra e2e paths
74
+
75
+ ```yaml
76
+ jobs:
77
+ validate:
78
+ uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@<sha> # <version>
79
+ with:
80
+ package-manager: pnpm # default: bun
81
+ e2e-extra-paths: '["wrangler.jsonc", "site.vars.json"]' # JSON array of globs
82
+ build-env: ${{ format('{{"PUBLIC_SITE_URL":"https://example.com","GIT_SHA":"{0}"}}', github.sha) }}
83
+ ```
84
+
85
+ With `pnpm`, the pnpm version comes from `packageManager` and Node from `volta`
86
+ or `engines` in `package.json`. The lockfile (`bun.lock` or `pnpm-lock.yaml`)
87
+ follows the package manager. `build-env` is a JSON object, visible in logs, so
88
+ no secrets.
89
+
46
90
  ## Workflow Types
47
91
 
48
92
  ### Validation / Checks
49
93
 
50
- Runs lint, typecheck, check for GPL licenses, e2e with Playwright
94
+ Runs lint, typecheck, check for GPL licenses, e2e with Playwright.
95
+
96
+ `site-ci.yml` runs these `package.json` scripts: `lint`, `check`, `build`,
97
+ `test:unit`, `check:licenses`, `test:e2e:full` (PRs into `main`),
98
+ `test:e2e:all` (PRs into `next` and `live`), `test:e2e:a11y` (`next` and
99
+ `live`), and `test:e2e:lighthouse` (`live`). A script the site does not define
100
+ is skipped with a notice, so none of them is required.
51
101
 
52
102
  ### Unlighthouse (performance / SEO budgets)
53
103
 
@@ -69,6 +119,19 @@ Unlighthouse version). Start from
69
119
  [`scripts/unlighthouse/unlighthouse.config.example.ts`](scripts/unlighthouse/unlighthouse.config.example.ts)
70
120
  and add `.unlighthouse/` to the site's `.gitignore`.
71
121
 
122
+ ### License policy
123
+
124
+ `site-ci.yml` runs `bun run check:licenses` when the lockfile or `scripts/`
125
+ change. Sites implement that script with the shared check, which runs
126
+ `license-checker` in the site's repo root and fails on GPL, AGPL, SSPL and
127
+ similar copyleft licenses (LGPL is allowed).
128
+
129
+ In the site's `package.json` (pin the tag):
130
+
131
+ ```json
132
+ "check:licenses": "bunx --package @taraxvoid/voidflow@<version> check-licenses"
133
+ ```
134
+
72
135
  ### Playwright preview config
73
136
 
74
137
  Shared `playwright.config` for Astro sites that run e2e against
@@ -97,6 +160,84 @@ Options: `ciPort` (required in CI), `runner` (default `bun`, e.g. `pnpm`),
97
160
  `timeout` (default 30000), `projects` (default Pixel 7 and Desktop Chrome),
98
161
  `testDir` (default `./test/e2e`). Requires `@playwright/test` in the site.
99
162
 
163
+ ## Dependency updates (Renovate)
164
+
165
+ [`default.json`](default.json) is the shared Renovate preset. Sites add a
166
+ `renovate.json`:
167
+
168
+ ```json
169
+ {
170
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
171
+ "extends": ["github>taraxvoid/voidflow"]
172
+ }
173
+ ```
174
+
175
+ It builds on `config:best-practices` (which pins GitHub Action digests), holds
176
+ updates for 3 days like `minimumReleaseAge` in `bunfig.toml` (except our own
177
+ package and security alerts), uses `chore(deps):` Conventional Commits, groups
178
+ actions, astro, biome and playwright, and runs on Monday mornings. Custom
179
+ managers keep three things current that Dependabot cannot see: the
180
+ `@taraxvoid/voidflow@x.y.z` pin inside `package.json` scripts, a lefthook
181
+ remote's `ref` tag, and tool versions in a `justfile` (annotate the line above
182
+ with `# renovate: datasource=... depName=...`). Requires the Renovate GitHub App
183
+ on the repo.
184
+
185
+ ||||||| 4041a59
186
+ ## Git hooks (lefthook)
187
+
188
+ [`lefthook/site.yml`](lefthook/site.yml) is the shared hook set for the site
189
+ stack, consumed as a lefthook remote. It calls the site's own `package.json`
190
+ scripts (`bun run --if-present`, so a missing script is skipped):
191
+
192
+ - `pre-commit`: dependency guard, `format` (formatted files are re-staged),
193
+ `lint:actions`, `check`, `test:unit`, and `check:licenses` / `audit` when the
194
+ lockfile changed.
195
+ - `commit-msg`: advisory Conventional Commits hint (never blocks).
196
+ - `pre-push`: bail if the remote branch is ahead, then `test:push`; skipped when
197
+ there is nothing new to push.
198
+
199
+ ```yaml
200
+ # lefthook.yml in the site
201
+ remotes:
202
+ - git_url: https://github.com/taraxvoid/voidflow
203
+ ref: v0.10.0 # a tag or branch; lefthook passes it to `git clone --branch`
204
+ configs:
205
+ - lefthook/site.yml
206
+
207
+ # Site-specific differences override the remote by name, e.g. skip tests that
208
+ # need a built dist/ before commit:
209
+ pre-commit:
210
+ commands:
211
+ unit:
212
+ run: bun run test:unit -- --exclude 'test/build.test.ts'
213
+ ```
214
+
215
+ Install the binary through mise (`lefthook = "<version>"` in `mise.toml`) and
216
+ set `"prepare": "lefthook install"` so `bun install` wires the hooks. `ref`
217
+ cannot be a commit SHA; pin a release tag.
218
+
219
+ ## Branch rulesets as code
220
+
221
+ Branch protection for the fleet lives in [`rulesets/index.ts`](rulesets/index.ts):
222
+ one canonical `main` / `next` / `live` definition plus a small per-repo table
223
+ (Netlify or not, check names, CODEOWNERS, extra bypass actors). Hand-edited
224
+ rulesets drift, and drift is how a `next` ruleset ends up requiring a check
225
+ name that no workflow reports any more.
226
+
227
+ ```sh
228
+ just rulesets-plan # read-only: diff every repo against the config
229
+ just rulesets-plan --repo soundry
230
+ just rulesets-plan --check # exit 1 on drift, for CI
231
+ just rulesets-apply # create/update rulesets to match
232
+ just rulesets-apply --prune # also delete rulesets a repo lists under `retire`
233
+ ```
234
+
235
+ Single-environment sites (a stable `main` that deploys to prod) manage only the
236
+ `main` tier; their old `next`/`live` rulesets are listed under `retire`.
237
+ Uses the `gh` CLI for auth (needs admin on the repos). Rulesets that are not in
238
+ the config are reported and left alone; only `retire` entries are ever deleted,
239
+ and only with `--prune`. It is repo tooling, not part of the published package.
240
+
100
241
  ## Deployments
101
242
 
102
243
  Example deployment job added to your workflow above. `resolve-env` maps the
@@ -125,6 +266,11 @@ jobs:
125
266
  cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
126
267
  ```
127
268
 
269
+ Sites with a single production environment and per-PR previews (no `next` or
270
+ `live` branch) pass `with: { single-environment: true }` to `resolve-env.yml`
271
+ (or the same input on `actions/branch-env-map`). `main` then maps to `prod` and
272
+ `pull_request` events map to `preview`; any other ref fails.
273
+
128
274
  ### Versioning
129
275
 
130
276
  This project uses semver, released with [release-please](https://github.com/googleapis/release-please)
@@ -149,13 +295,13 @@ This repo validates its own workflows and composite actions (`.github/workflows/
149
295
 
150
296
  - **actionlint**: workflow schema/logic; also shellchecks `run:` steps in `.github/workflows/*.yml` automatically (`shellcheck` ships on `ubuntu-latest`)
151
297
  - **check-jsonschema**: schema-checks `actions/**/action.yml` and the workflow files against [SchemaStore](https://www.schemastore.org/)'s `github-action.json` / `github-workflow.json`
152
- - **shellcheck** (`scripts/shellcheck-actions.sh`): checks `run:` steps inside `actions/**/action.yml`, which actionlint doesn't reach
298
+ - **shellcheck** (`scripts/shellcheck-actions.ts`): checks `run:` steps inside `actions/**/action.yml`, which actionlint doesn't reach
153
299
  - **zizmor**: security audit (unpinned refs, script injection via `${{ }}` in `run:`, excess permissions, etc.)
154
300
 
155
301
  ### Local dev setup
156
302
 
157
303
  ```sh
158
- brew install just lefthook actionlint shellcheck yq act uv
304
+ brew install just lefthook actionlint shellcheck bun act uv
159
305
  lefthook install
160
306
  ```
161
307
 
@@ -166,6 +312,6 @@ lefthook install
166
312
 
167
313
  **Colima users:** `.actrc` already disables the docker-socket mount (`--container-daemon-socket -`). `act` binds `/var/run/docker.sock` by default, which doesn't exist under Colima and fails with `operation not supported`. None of these workflow steps need docker-in-docker, so this is safe.
168
314
 
169
- **Run `just dry-run` from a normal checkout, not a linked git worktree.** `act` copies the working tree via `docker cp` rather than a real clone, so a worktree's `.git` pointer back to the parent repo doesn't resolve inside the container, so `git ls-files`-based steps (schema validation, `scripts/shellcheck-actions.sh`) silently see zero files instead of erroring. Verified clean end-to-end (`🏁 Job succeeded`) from a plain clone.
315
+ **Run `just dry-run` from a normal checkout, not a linked git worktree.** `act` copies the working tree via `docker cp` rather than a real clone, so a worktree's `.git` pointer back to the parent repo doesn't resolve inside the container, so `git ls-files`-based steps (schema validation, `scripts/shellcheck-actions.ts`) silently see zero files instead of erroring. Verified clean end-to-end (`🏁 Job succeeded`) from a plain clone.
170
316
 
171
317
  Provided as is under the [MIT license](LICENSE). Issues and pull requests are welcome.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taraxvoid/voidflow",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "description": "Shared workflows, actions and tooling for @taraxvoid sites",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -25,7 +25,8 @@
25
25
  "provenance": true
26
26
  },
27
27
  "bin": {
28
- "unlighthouse-runner": "scripts/unlighthouse/run.ts"
28
+ "unlighthouse-runner": "scripts/unlighthouse/run.ts",
29
+ "check-licenses": "scripts/check-licenses.ts"
29
30
  },
30
31
  "exports": {
31
32
  "./playwright": {
@@ -36,7 +37,8 @@
36
37
  },
37
38
  "files": [
38
39
  "playwright",
39
- "scripts/unlighthouse"
40
+ "scripts/unlighthouse",
41
+ "scripts/check-licenses.ts"
40
42
  ],
41
43
  "engines": {
42
44
  "bun": ">=1.4.0"
@@ -48,6 +50,7 @@
48
50
  "@playwright/test": ">=1.40"
49
51
  },
50
52
  "devDependencies": {
51
- "@playwright/test": "^1.40.0"
53
+ "@playwright/test": "^1.40.0",
54
+ "@socketsecurity/bun-security-scanner": "^1.1.3"
52
55
  }
53
56
  }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Shared license policy check for the Astro/bun site stack: fail on GPL kudzu.
4
+ *
5
+ * Runs `license-checker` against the current working directory (the caller's
6
+ * repo root) and exits non-zero if any installed package carries a blocked
7
+ * license.
8
+ *
9
+ * Usage: bun check-licenses.ts
10
+ */
11
+
12
+ import { spawnSync } from 'node:child_process'
13
+
14
+ export const FAIL_ON = [
15
+ 'GPL-1.0',
16
+ 'GPL-1.0-only',
17
+ 'GPL-1.0-or-later',
18
+ 'GPL-2.0',
19
+ 'GPL-2.0-only',
20
+ 'GPL-2.0-or-later',
21
+ 'GPL-3.0',
22
+ 'GPL-3.0-only',
23
+ 'GPL-3.0-or-later',
24
+ 'AGPL-1.0',
25
+ 'AGPL-1.0-only',
26
+ 'AGPL-1.0-or-later',
27
+ 'AGPL-2.0',
28
+ 'AGPL-2.0-only',
29
+ 'AGPL-2.0-or-later',
30
+ 'AGPL-3.0',
31
+ 'AGPL-3.0-only',
32
+ 'AGPL-3.0-or-later',
33
+ 'SSPL-1.0',
34
+ 'OSL-2.1',
35
+ 'OSL-3.0',
36
+ 'CPAL-1.0',
37
+ 'EUPL-1.1',
38
+ 'EUPL-1.2',
39
+ 'CECILL-2.1',
40
+ // LGPL is deliberately NOT in this list - it only imposes obligations on
41
+ // modifying/statically linking the library, not on depending on it as-is.
42
+ ].join(';')
43
+
44
+ const result = spawnSync(
45
+ 'bunx',
46
+ ['license-checker', '--summary', '--failOn', FAIL_ON],
47
+ { cwd: process.cwd(), stdio: 'inherit' },
48
+ )
49
+
50
+ if (result.error) {
51
+ console.error(
52
+ `\ncheck:licenses failed - could not run license-checker: ${result.error.message}`,
53
+ )
54
+ process.exit(1)
55
+ }
56
+
57
+ if (result.status !== 0) {
58
+ console.error(
59
+ '\ncheck:licenses failed - at least one disallowed license was found.',
60
+ )
61
+ process.exit(1)
62
+ }
63
+
64
+ console.log(
65
+ '\ncheck:licenses passed - no blocked licenses found in any workspace.',
66
+ )