@xenos1996/usat 1.0.0 → 1.2.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/docs/ci-integration.md +31 -9
- package/docs/release.md +87 -0
- package/package.json +3 -1
- package/rules/core/testing.yaml +5 -1
package/docs/ci-integration.md
CHANGED
|
@@ -128,18 +128,40 @@ improvement — the thing a single audit can never do.
|
|
|
128
128
|
|
|
129
129
|
USAT audits itself with the full stack — copy what fits:
|
|
130
130
|
|
|
131
|
-
| Workflow
|
|
132
|
-
|
|
|
133
|
-
| `ci.yml`
|
|
134
|
-
| `self-audit.yml`
|
|
135
|
-
| `scorecard.yml`
|
|
136
|
-
| `automerge.yml`
|
|
137
|
-
| `gitleaks-pin.yml`
|
|
138
|
-
| `release.yml`
|
|
131
|
+
| Workflow | What it does |
|
|
132
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
133
|
+
| `ci.yml` | lint+format+typecheck · Vitest with coverage thresholds · build + CLI smoke · rule-pack validation · npm audit + gitleaks + license scan · **hygiene** (`check-adrs` + `check-docs`) |
|
|
134
|
+
| `self-audit.yml` | `usat audit . --depth deep --fail-on critical` on every PR, score as PR comment |
|
|
135
|
+
| `scorecard.yml` | OpenSSF Scorecard monthly + on push (API-verified hygiene; SARIF to Security tab) |
|
|
136
|
+
| `automerge.yml` | Dependabot patch/minor auto-merge once CI is green (majors stay manual) |
|
|
137
|
+
| `gitleaks-pin.yml` | Monthly check that the curl-pinned gitleaks binary in `ci.yml` is current (no bot watches it) — opens a deduped issue when stale |
|
|
138
|
+
| `release.yml` | Tag push `v*` → OIDC trusted publishing to npmjs (no long-lived token) + `--provenance` + CycloneDX SBOM artifact, then mirror publish to GitHub Packages (populates the repo Packages tab) |
|
|
139
|
+
| `release-please.yml` | Conventional commits → open Release PR (bump + CHANGELOG as reviewable diff); merging it cuts the tag that fires `release.yml` |
|
|
140
|
+
| `commits` in `ci.yml` | Lints PR commit messages (commitlint) — releases are computed from history, so history must parse |
|
|
139
141
|
|
|
140
142
|
Release setup note: trusted publishing needs a one-time owner step on
|
|
141
143
|
npmjs.com (package Settings → Trusted Publisher → this repo + workflow)
|
|
142
|
-
before the first OIDC publish succeeds.
|
|
144
|
+
before the first OIDC publish succeeds. Full lifecycle, setups, rotation,
|
|
145
|
+
and every failure met so far: [release.md](release.md).
|
|
146
|
+
|
|
147
|
+
## How a release happens (developer-style, no manual versioning)
|
|
148
|
+
|
|
149
|
+
1. Land PRs with Conventional Commits titles (`feat:`, `fix:`, `docs:`,
|
|
150
|
+
`refactor:` …) — squash-merge so the title becomes the commit.
|
|
151
|
+
`feat` → minor bump, `fix` → patch, `BREAKING CHANGE:` footer → major.
|
|
152
|
+
Anything else (docs, chore, test) rides along without bumping.
|
|
153
|
+
2. release-please keeps one open **Release PR** updated: version bump in
|
|
154
|
+
`package.json` + CHANGELOG entries, as a diff you review like code.
|
|
155
|
+
3. Merge the Release PR → tag `vX.Y.Z` is cut → `release.yml` publishes
|
|
156
|
+
via OIDC with provenance + SBOM. Tags are the release act; never push
|
|
157
|
+
`v*` tags by hand (first bootstrap tag `v1.0.0` excepted).
|
|
158
|
+
4. release-please itself authenticates with a fine-grained PAT
|
|
159
|
+
(`RELEASE_PLEASE_TOKEN`, repo-scoped: Contents, PRs, Issues
|
|
160
|
+
read+write) — **not** `GITHUB_TOKEN`. Tags pushed by `GITHUB_TOKEN`
|
|
161
|
+
do not trigger downstream workflows, so with the default token the
|
|
162
|
+
tag lands, the GitHub Release is created… and `release.yml` never
|
|
163
|
+
fires. Nothing reaches npm. This failure is silent by design
|
|
164
|
+
(loop prevention) — the PAT is load-bearing, not optional.
|
|
143
165
|
|
|
144
166
|
## Choosing a depth in CI
|
|
145
167
|
|
package/docs/release.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Releasing USAT — operations runbook
|
|
2
|
+
|
|
3
|
+
The release pipeline is fully automated. Normal operation requires nothing
|
|
4
|
+
beyond merging PRs. This file exists so future-you (or a successor) can
|
|
5
|
+
reconstruct _why_ every piece is shaped the way it is, and what to do when
|
|
6
|
+
something breaks. It is the durable memory of the sessions that built it.
|
|
7
|
+
|
|
8
|
+
## The chain (normal operation — nothing to do)
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
conventional commit on master
|
|
12
|
+
│ feat → minor · fix → patch · BREAKING CHANGE → major
|
|
13
|
+
│ (docs/chore/test ride along without bumping)
|
|
14
|
+
▼
|
|
15
|
+
release-please opens/updates ONE Release PR
|
|
16
|
+
(version bump + CHANGELOG entries as a reviewable diff)
|
|
17
|
+
│ human merges it ← the only manual step, and it is code review
|
|
18
|
+
▼
|
|
19
|
+
tag vX.Y.Z cut automatically
|
|
20
|
+
▼
|
|
21
|
+
release.yml publishes: OIDC → npmjs (+ provenance + SBOM artifact),
|
|
22
|
+
then mirrors the same tarball to GitHub Packages (repo Packages tab)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
What you do: write conventional titles, review PRs, merge the Release PR.
|
|
26
|
+
Everything else — bump arithmetic, CHANGELOG entries, tags, publishing,
|
|
27
|
+
provenance, SBOM — happens on its own.
|
|
28
|
+
|
|
29
|
+
## One-time setups (done — do not redo unless broken)
|
|
30
|
+
|
|
31
|
+
| # | Setup | Where / state |
|
|
32
|
+
| --- | ------------------------------------------------------------- | --------------------------------------------------------- |
|
|
33
|
+
| 1 | Package exists on npmjs as `@xenos1996/usat` (scoped: the | Done at 1.0.0. Never republish a version. |
|
|
34
|
+
| | bare name `usat` is blocked by the typosquat filter) | |
|
|
35
|
+
| 2 | OIDC trusted publisher (org `Er-Sajan-PLG`, repo | Package page → Settings → Trusted Publisher. |
|
|
36
|
+
| | `software-auditing-template`, workflow `release.yml`, no env) | Exact basename — full paths do not match. |
|
|
37
|
+
| 3 | Trusted publisher may **publish directly** | Same page (checkbox). Without it, PUTs 404. |
|
|
38
|
+
| 4 | Publishing access: strictest (2FA required, no bypass tokens) | Same page. OIDC works with either option. |
|
|
39
|
+
| 5 | `RELEASE_PLEASE_TOKEN`: fine-grained PAT, this repo only — | Repo Settings → Secrets → Actions. **Check its expiry** |
|
|
40
|
+
| | Contents + PRs + Issues read+write | (Settings → Developer settings → Tokens): when it lapses, |
|
|
41
|
+
| | | Release PRs silently stop appearing. Rotate yearly. |
|
|
42
|
+
|
|
43
|
+
The bootstrap token used for the first manual publish is deleted. No
|
|
44
|
+
static credential that can publish exists anymore — only OIDC (CI) and
|
|
45
|
+
2FA (humans).
|
|
46
|
+
|
|
47
|
+
## Recurring (calendar, not automation)
|
|
48
|
+
|
|
49
|
+
- **PAT expiry** — the one thing that silently breaks releases. Check the
|
|
50
|
+
date when the reminder fires; generate a replacement with identical
|
|
51
|
+
scope, swap the secret, delete the old token.
|
|
52
|
+
- **First-run review of each Release PR** — read the CHANGELOG diff;
|
|
53
|
+
release-please derives it from titles, so a sloppy title ships a sloppy
|
|
54
|
+
note. Fix by amending the title before merge (it recalculates).
|
|
55
|
+
- **Scorecard / Security tab** — glance monthly; the workflow already runs.
|
|
56
|
+
|
|
57
|
+
## Troubleshooting (every failure hit so far, in order)
|
|
58
|
+
|
|
59
|
+
| Symptom | Cause | Fix |
|
|
60
|
+
| ------------------------------------------------------ | ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
61
|
+
| `403 … too similar to existing packages` on publish | npm typosquat filter on the bare name | Scoped name (`@xenos1996/usat`). Decided, shipped. |
|
|
62
|
+
| `bin[usat]` "invalid and removed" warning on publish | npm v12 rejects `./`-prefixed bin targets; tarball ships with **no executable** | `bin` value is `dist/cli.js` (no prefix). Never re-add `./`. |
|
|
63
|
+
| `npm sbom -o` → `EUNKNOWNCONFIG` | No `-o` flag exists; SBOM goes to stdout | Redirect: `npm sbom … > sbom.cdx.json`, after a clean `npm ci` (partial trees fail with `ESBOMPROBLEMS`). |
|
|
64
|
+
| PUT 404 with provenance signed fine | Runner npm too old for the registry OIDC exchange (needs npm ≥ 11.5.1 / Node ≥ 22.14) | `release.yml` pins Node 24 + `npm@^11.15.0` floor. Do not downgrade. |
|
|
65
|
+
| Tag cut, GitHub Release created, **nothing published** | Tags pushed by `GITHUB_TOKEN` never fire downstream workflows (loop prevention) | release-please uses the PAT, never the default token. |
|
|
66
|
+
| Release PR lint red on `CHANGELOG.md` | release-please writes double blank lines; prettier wants single | `CHANGELOG.md` is prettier-ignored (machine-written). |
|
|
67
|
+
| `Unable to resolve action ossf/scorecard-action@v2` | Upstream publishes no `v2` major tag | Pinned exact `v2.4.4`. Check for newer semver occasionally. |
|
|
68
|
+
| `usat --help` audited the repo | Arg parser files `--flags`, never positionals; the switch cases were dead code | Fixed in `cli.ts` with regression tests. Do not reintroduce flag handling without a test. |
|
|
69
|
+
| `SEC-003` failing on `https://` URLs (pre-1.0 history) | Pattern used `https?://` for a plaintext-HTTP rule | Fixed to `http://`; rule carries a `NOTE:` comment. See `tests/rules.test.ts`. |
|
|
70
|
+
|
|
71
|
+
## Manual fallback
|
|
72
|
+
|
|
73
|
+
If automation ever wedges: Actions → **Release** → Run workflow (on
|
|
74
|
+
`master`) publishes whatever `package.json` holds. Safe to re-run — a
|
|
75
|
+
duplicate version fails closed at the registry with nothing mutated.
|
|
76
|
+
Never push `v*` tags by hand; the tag is the release act and belongs to
|
|
77
|
+
release-please (bootstrap tag `v1.0.0` excepted).
|
|
78
|
+
|
|
79
|
+
## Decisions with permanent consequences
|
|
80
|
+
|
|
81
|
+
- **No moving `v1` tag.** It would retrigger `release.yml` (`v*` matches)
|
|
82
|
+
and fail on the duplicate version. Docs pin exact versions instead.
|
|
83
|
+
- **No semantic-release.** Rule-pack content keeps its human gate; fully
|
|
84
|
+
automatic publishing is the wrong risk profile here (see ROADMAP.md).
|
|
85
|
+
- **npmjs is the source of truth; GitHub Packages is a mirror.** Old
|
|
86
|
+
versions were never backfilled to GPR — two sources of truth for dead
|
|
87
|
+
versions is worse than a thin Packages tab for one cycle.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenos1996/usat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Universal Software Audit Template — an open-source, self-adapting audit framework for any project, any stack, any stage",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
"yaml": "^2.6.1"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
|
+
"@commitlint/cli": "^21.2.2",
|
|
86
|
+
"@commitlint/config-conventional": "^21.2.2",
|
|
85
87
|
"@eslint/js": "^10.0.1",
|
|
86
88
|
"@types/node": "^26.4.1",
|
|
87
89
|
"@vitest/coverage-v8": "^5.0.0",
|
package/rules/core/testing.yaml
CHANGED
|
@@ -120,7 +120,11 @@ rules:
|
|
|
120
120
|
- { fact: 'maturity:beta' }
|
|
121
121
|
check:
|
|
122
122
|
kind: grep_present
|
|
123
|
-
|
|
123
|
+
# NOTE: `coverage\s*:\s*\{` covers Vitest-style `coverage: { thresholds:
|
|
124
|
+
# … }` blocks — the earlier `coverage\s*{` (no colon) missed exactly
|
|
125
|
+
# the config form this repo itself uses, so the rule failed USAT's own
|
|
126
|
+
# self-audit the week thresholds were added. Keep both alternatives.
|
|
127
|
+
pattern: '(coverageThreshold|failUnder|--fail-under|min-coverage|coverage\s*\{|coverage\s*:\s*\{|\[tool\.coverage\.report\]\s*\n[^\n]*fail_under)'
|
|
124
128
|
include:
|
|
125
129
|
[
|
|
126
130
|
'package.json',
|