@xenos1996/usat 1.1.0 → 1.3.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.
@@ -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.
@@ -276,3 +276,20 @@ usat audit . --include stacks/mobile --depth deep
276
276
 
277
277
  A pack with a YAML syntax error is skipped with a warning on stderr — the audit never
278
278
  crashes because of a bad rule file.
279
+
280
+ ## Starting from `usat bootstrap`
281
+
282
+ For a language with no shipped pack, `usat bootstrap <path> [--out <dir>]`
283
+ drafts a starter pack from the curated catalog (or generic judgement
284
+ prompts for unknown languages). The draft is a proposal, not a verdict —
285
+ see ADR-0012. The acceptance ritual before registering it in
286
+ `rules/index.yaml`:
287
+
288
+ 1. Read every pattern; delete any that misfires on the target codebase.
289
+ 2. Audit one project WITH the problem and one WITHOUT it; both runs must
290
+ behave (`usat audit --rules-dir` accepts an unregistered pack dir, so
291
+ the review never pollutes the shipped registry).
292
+ 3. Add FP _and_ FN regression tests to `tests/rules.test.ts`.
293
+ 4. Register the reviewed file in `rules/index.yaml` and watch the
294
+ self-audit-adjacent gates (`check-docs` rule floor, e2e uniqueness)
295
+ stay green.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenos1996/usat",
3
- "version": "1.1.0",
3
+ "version": "1.3.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",
@@ -136,7 +136,9 @@ rules:
136
136
  # bare alternative also matched `regex.exec(body)`, and a bare `body`
137
137
  # matched document.body / res.body — both flagged ordinary code. The
138
138
  # lookbehind drops the method-call form; req./params/input keep signal.
139
- pattern: '\b(eval\s*\(|new Function\s*\(|execSync\s*\(\s*[^\n)]*\$\{|(?<!\.)exec\s*\(\s*[^\n)]*(req\.|params|input)|setTimeout\s*\(\s*[''"`])'
139
+ # The quote lookbehind on `eval` drops prose mentions ('eval() does X'
140
+ # in docs and rule descriptions); real calls are never quote-prefixed.
141
+ pattern: '\b((?<![''"`])eval\s*\(|new Function\s*\(|execSync\s*\(\s*[^\n)]*\$\{|(?<!\.)exec\s*\(\s*[^\n)]*(req\.|params|input)|setTimeout\s*\(\s*[''"`])'
140
142
  include: ['**/*.{ts,tsx,js,jsx,mjs,cjs,py,php,rs}']
141
143
  exclude: ['**/*.test.*', '**/*.spec.*', '**/test/**', '**/tests/**', '**/scripts/**']
142
144
  why: 'eval and friends turn untrusted strings into executable code. Almost every RCE starts here.'