@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 +150 -4
- package/package.json +7 -4
- package/scripts/check-licenses.ts +66 -0
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
+
)
|