@intentius/chant 0.53.0 → 0.54.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/dist/audit/catalog.d.ts +4 -0
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts +53 -0
- package/dist/audit/nginx.d.ts.map +1 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/carve-apply.d.ts.map +1 -1
- package/dist/cli/commands/carve-status.d.ts +56 -0
- package/dist/cli/commands/carve-status.d.ts.map +1 -0
- package/dist/cli/handlers/carve-status.d.ts +9 -0
- package/dist/cli/handlers/carve-status.d.ts.map +1 -0
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/op-progress.d.ts +37 -4
- package/dist/cli/handlers/op-progress.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +61 -1
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +9 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +3 -1
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +2 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/graph-ir.d.ts +7 -0
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/lexicon.d.ts +8 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/converge-ledger.d.ts +81 -1
- package/dist/lifecycle/converge-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +43 -1
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +55 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +15 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/terraform/manifest.d.ts +31 -6
- package/dist/terraform/manifest.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/audit/catalog.ts +35 -0
- package/src/audit/edge-init-safety.test.ts +36 -3
- package/src/audit/nginx.test.ts +180 -0
- package/src/audit/nginx.ts +379 -0
- package/src/audit/rules-doc.ts +1 -0
- package/src/cli/commands/audit.ts +8 -3
- package/src/cli/commands/carve-apply.test.ts +4 -1
- package/src/cli/commands/carve-apply.ts +4 -2
- package/src/cli/commands/carve-bridge.test.ts +2 -1
- package/src/cli/commands/carve-emit-state.test.ts +3 -1
- package/src/cli/commands/carve-status.test.ts +116 -0
- package/src/cli/commands/carve-status.ts +163 -0
- package/src/cli/handlers/carve-status.ts +30 -0
- package/src/cli/handlers/components.ts +5 -1
- package/src/cli/handlers/graph.ts +3 -0
- package/src/cli/handlers/op-progress.test.ts +67 -1
- package/src/cli/handlers/op-progress.ts +70 -14
- package/src/cli/handlers/operator.test.ts +302 -1
- package/src/cli/handlers/operator.ts +193 -5
- package/src/cli/handlers/run.ts +15 -14
- package/src/cli/main.test.ts +19 -0
- package/src/cli/main.ts +34 -5
- package/src/cli/registry.ts +9 -1
- package/src/components/auto-release.ts +4 -1
- package/src/components/cli-support.ts +4 -2
- package/src/graph-ir.ts +7 -0
- package/src/lexicon.ts +8 -0
- package/src/lifecycle/converge-ledger.test.ts +110 -0
- package/src/lifecycle/converge-ledger.ts +110 -2
- package/src/lifecycle/gate-ledger.test.ts +81 -1
- package/src/lifecycle/gate-ledger.ts +64 -1
- package/src/lifecycle/release-ledger.test.ts +64 -0
- package/src/lifecycle/release-ledger.ts +79 -1
- package/src/op/activity-contract.ts +14 -0
- package/src/terraform/manifest.test.ts +52 -0
- package/src/terraform/manifest.ts +72 -10
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ComponentStatusRow } from "./status.js";
|
|
2
|
+
export declare function sanitizeLedgerText(raw: string, maxLen?: number): string;
|
|
1
3
|
/** One rule's outcome within a tick. */
|
|
2
4
|
export interface ConvergeRuleOutcome {
|
|
3
5
|
ruleId: string;
|
|
@@ -15,13 +17,70 @@ export interface ConvergeRuleOutcome {
|
|
|
15
17
|
op?: string;
|
|
16
18
|
/** The gate's signal name, for `action: "gated"`. */
|
|
17
19
|
gateName?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Where this gate's approval happens (#2028), for `action: "gated"` — the
|
|
22
|
+
* PR carrying the change in a gate-as-PR flow, or whatever review surface
|
|
23
|
+
* the dispatching environment knows about.
|
|
24
|
+
*
|
|
25
|
+
* The pending fact is the one a human has to act on, and it used to carry
|
|
26
|
+
* no link at all: `chant operator status`'s pending row was
|
|
27
|
+
* `{rule, op, gate}` and the only affordance it could print was a shell
|
|
28
|
+
* command. Absent when there genuinely is no address — a local tick with no
|
|
29
|
+
* PR behind it — never a synthesized one. See
|
|
30
|
+
* `./gate-ledger.ts`'s `resolveApprovalUrl` for where it comes from, and
|
|
31
|
+
* `GateResolutionRecord.url` for the resolved counterpart.
|
|
32
|
+
*/
|
|
33
|
+
url?: string;
|
|
18
34
|
/** The report reason, for `action: "reported"` (including a flap-damped rule's forced report) — and the human-readable explanation for `action: "gated"`. */
|
|
19
35
|
reason?: string;
|
|
20
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* One component's verdict as the tick observed it (#2027) — the per-entity
|
|
39
|
+
* layer behind the tick's single aggregate `status`.
|
|
40
|
+
*
|
|
41
|
+
* A deliberate subset of `ComponentStatusRow`: the five verdict-bearing
|
|
42
|
+
* fields, joined on the same `component` key `chant components status --live
|
|
43
|
+
* --json` emits, and none of the heavy ones. `recorded`, `build` and
|
|
44
|
+
* `componentBom` are dropped on purpose — they are release/build-ledger
|
|
45
|
+
* content, already readable by that same key, and a tick record is one line
|
|
46
|
+
* of JSON appended every tick forever. `detail` goes through
|
|
47
|
+
* {@link sanitizeLedgerText} for the same reason.
|
|
48
|
+
*/
|
|
49
|
+
export interface ConvergeComponentVerdict {
|
|
50
|
+
component: string;
|
|
51
|
+
reconciliation: ComponentStatusRow["reconciliation"];
|
|
52
|
+
/** Human-readable detail backing the verdict, capped to one line. */
|
|
53
|
+
detail: string;
|
|
54
|
+
/** "Observed live", when live evidence was gathered. Absent means "did not look" or "could not look" — see `unobserved`. */
|
|
55
|
+
live?: boolean;
|
|
56
|
+
/** Why live state could not be read for this component (#1089). Mutually exclusive with `live`; this is the row that tripped an aggregate `status: "unknown"`. */
|
|
57
|
+
unobserved?: {
|
|
58
|
+
reason: string;
|
|
59
|
+
detail?: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Project the tick's `ComponentStatusRow[]` down to what the ledger keeps.
|
|
64
|
+
* Pure; row order is preserved, so a consumer sees components in the same
|
|
65
|
+
* order the status join produced them.
|
|
66
|
+
*/
|
|
67
|
+
export declare function componentVerdicts(rows: readonly ComponentStatusRow[]): ConvergeComponentVerdict[];
|
|
21
68
|
/** One immutable converge-tick record. */
|
|
22
69
|
export interface ConvergeTickRecord {
|
|
23
70
|
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
24
71
|
version: 1;
|
|
72
|
+
/**
|
|
73
|
+
* Stable tick id (#2027) — the one thing an outcome, a gate fact or a
|
|
74
|
+
* remediation can point at. Before this, a tick's identity was the
|
|
75
|
+
* `(op, env, timestamp)` triple, so two ticks landing in the same ISO
|
|
76
|
+
* second were indistinguishable and nothing could reference one.
|
|
77
|
+
*
|
|
78
|
+
* Minted by {@link appendConvergeRecord} with `randomUUID()` (the same
|
|
79
|
+
* mint `./lease.ts` uses for a lease token) when the caller doesn't supply
|
|
80
|
+
* one. Optional on the type because `version: 1` records written before
|
|
81
|
+
* #2027 have none — a reader must handle its absence, not assume it.
|
|
82
|
+
*/
|
|
83
|
+
id?: string;
|
|
25
84
|
/** The ConvergeOp's name (`OpConfig.name`). */
|
|
26
85
|
op: string;
|
|
27
86
|
env: string;
|
|
@@ -31,6 +90,18 @@ export interface ConvergeTickRecord {
|
|
|
31
90
|
firedRuleIds: string[];
|
|
32
91
|
/** Per-rule outcome, for every fired rule. */
|
|
33
92
|
outcomes: ConvergeRuleOutcome[];
|
|
93
|
+
/**
|
|
94
|
+
* The per-component verdicts this tick observed (#2027), behind the
|
|
95
|
+
* aggregate counts in `summary`.
|
|
96
|
+
*
|
|
97
|
+
* The tick derives these to compute `summary.drifted` and the whole-tick
|
|
98
|
+
* `status`, and used to throw them away — so a reader could say "this
|
|
99
|
+
* environment drifted twice this hour" but could not colour the node that
|
|
100
|
+
* drifted, or name the single unobserved component whose `unknown` verdict
|
|
101
|
+
* refused remediation for everything else. Optional because `version: 1`
|
|
102
|
+
* records written before #2027 have none; absent is not "no components".
|
|
103
|
+
*/
|
|
104
|
+
components?: ConvergeComponentVerdict[];
|
|
34
105
|
/** Aggregate counts backing the tick's one log line. */
|
|
35
106
|
summary: {
|
|
36
107
|
drifted: number;
|
|
@@ -52,6 +123,13 @@ export type ConvergeTickRecordInput = Omit<ConvergeTickRecord, "version">;
|
|
|
52
123
|
* `pushLifecycle` (./git.ts) afterward, same two-step shape every other
|
|
53
124
|
* ledger write here uses.
|
|
54
125
|
*
|
|
126
|
+
* Mints `record.id` (#2027) when the input doesn't carry one, so every tick
|
|
127
|
+
* written from here on is referenceable. Unlike `timestamp`, which stays
|
|
128
|
+
* caller-supplied because library code never calls `Date.now()` internally,
|
|
129
|
+
* an id has nothing for a caller to decide — the mint lives here so no
|
|
130
|
+
* writer can forget it. An explicit `input.id` still wins, which is what a
|
|
131
|
+
* test asserting an exact record uses.
|
|
132
|
+
*
|
|
55
133
|
* Retries the whole read-modify-write cycle (#1485) on `RefCASConflictError`
|
|
56
134
|
* — `writeBlobToPath`'s ref write is CAS-guarded, so a concurrent writer to
|
|
57
135
|
* a *different* env's file on the same orphan branch (two operators ticking
|
|
@@ -71,7 +149,9 @@ export declare function appendConvergeRecord(input: ConvergeTickRecordInput, opt
|
|
|
71
149
|
cwd?: string;
|
|
72
150
|
}): Promise<{
|
|
73
151
|
commit: string;
|
|
74
|
-
record: ConvergeTickRecord
|
|
152
|
+
record: ConvergeTickRecord & {
|
|
153
|
+
id: string;
|
|
154
|
+
};
|
|
75
155
|
}>;
|
|
76
156
|
/** Read every tick record for `environment`, oldest first. Malformed lines are skipped, not thrown on — a corrupted or hand-edited ledger degrades gracefully, the same stance `readReleaseLedger` takes. */
|
|
77
157
|
export declare function readConvergeLedger(environment: string, opts?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"converge-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/converge-ledger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"converge-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/converge-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The address of the approval surface for a gate, resolved from the CI
|
|
3
|
+
* environment (#2028).
|
|
4
|
+
*
|
|
5
|
+
* #1485's argument for gate-as-fact was that approval gets an address:
|
|
6
|
+
* "gate-as-PR gives approval a URL, a review surface, and CODEOWNERS as the
|
|
7
|
+
* authorization model." What shipped recorded the gate and not the address,
|
|
8
|
+
* so a pending-approval card had nothing to link to and gate-as-PR stayed a
|
|
9
|
+
* convention. This is the narrow, honest half of that: when a tick (or a
|
|
10
|
+
* `chant approve`) runs inside the PR/MR job that carries the change, the
|
|
11
|
+
* loop genuinely knows where approval happens, and says so. Anywhere else it
|
|
12
|
+
* returns `undefined` and the field is simply absent — never a guess, never a
|
|
13
|
+
* synthesized link.
|
|
14
|
+
*
|
|
15
|
+
* The env-var fallback chain is the same one `--actor` and `--run-id` already
|
|
16
|
+
* use (`../cli/handlers/components.ts`): GitHub Actions first, then GitLab CI.
|
|
17
|
+
*
|
|
18
|
+
* - GitHub Actions on a `pull_request` event: `GITHUB_SERVER_URL` +
|
|
19
|
+
* `GITHUB_REPOSITORY` + the PR number, which `GITHUB_REF_NAME` carries as
|
|
20
|
+
* `<n>/merge`. A push-event run has no PR, so it resolves to nothing.
|
|
21
|
+
* - GitLab CI on a merge-request pipeline: `CI_MERGE_REQUEST_PROJECT_URL` +
|
|
22
|
+
* `CI_MERGE_REQUEST_IID`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveApprovalUrl(env?: NodeJS.ProcessEnv): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Whether `raw` is an address worth recording as one: an absolute `http`/
|
|
27
|
+
* `https` URL. A gate's address is a link a reader is expected to follow, so
|
|
28
|
+
* a relative path or a `file:`/`javascript:` scheme is refused at the CLI
|
|
29
|
+
* boundary rather than written into an immutable record.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isApprovalUrl(raw: string): boolean;
|
|
1
32
|
/** One immutable gate-resolution record. */
|
|
2
33
|
export interface GateResolutionRecord {
|
|
3
34
|
/** Schema version, so an incompatible future shape is detected before being misread. */
|
|
@@ -10,8 +41,19 @@ export interface GateResolutionRecord {
|
|
|
10
41
|
resolvedBy: string;
|
|
11
42
|
/** ISO-8601 timestamp, caller-supplied (library code never calls `Date.now()` internally). */
|
|
12
43
|
timestamp: string;
|
|
13
|
-
/** Optional free-text context
|
|
44
|
+
/** Optional free-text context. Before #2028 this was also where a PR link went by convention; put the link in {@link GateResolutionRecord.url} instead and leave this for prose. */
|
|
14
45
|
note?: string;
|
|
46
|
+
/**
|
|
47
|
+
* The address this resolution happened at (#2028) — the PR that carried the
|
|
48
|
+
* change, the review thread, whatever the approval surface was. Typed, so
|
|
49
|
+
* "resolved by this PR" is machine-readable instead of a reader sniffing
|
|
50
|
+
* `note` for something that looks like a link.
|
|
51
|
+
*
|
|
52
|
+
* `chant approve --url` sets it; absent when the resolver genuinely had no
|
|
53
|
+
* address (a human at a terminal, no PR). Always an absolute `http`/`https`
|
|
54
|
+
* URL — see {@link isApprovalUrl}.
|
|
55
|
+
*/
|
|
56
|
+
url?: string;
|
|
15
57
|
}
|
|
16
58
|
export type GateResolutionInput = Omit<GateResolutionRecord, "version">;
|
|
17
59
|
/** Append one immutable gate-resolution record. Does not push to the remote — call `pushLifecycle` (./git.ts) afterward, same two-step shape every other ledger write here uses. Retries on `RefCASConflictError` the same way `appendConvergeRecord` does (./converge-ledger.ts) — a concurrent writer to a different op's/env's file on the same orphan branch is the ordinary case, not an edge case. The baseline read must be `readPathSha` + `readBlobBySha` rather than `readBlobFromPath`, so the exact sha `existing` came from can be passed as `expectPriorPathSha` — see `writeBlobToPath` (./git.ts) for the race that closes. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/gate-ledger.ts"],"names":[],"mappings":"AA4CA,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,OAAO,EAAE,CAAC,CAAC;IACX,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,yHAAyH;IACzH,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"gate-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/gate-ledger.ts"],"names":[],"mappings":"AA4CA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAY3F;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED,4CAA4C;AAC5C,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,OAAO,EAAE,CAAC,CAAC;IACX,6CAA6C;IAC7C,EAAE,EAAE,MAAM,CAAC;IACX,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,yHAAyH;IACzH,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,SAAS,EAAE,MAAM,CAAC;IAClB,oLAAoL;IACpL,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC;AAMxE,+mBAA+mB;AAC/mB,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,mBAAmB,EAC1B,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,CAAC,CAqB3D;AAED,oPAAoP;AACpP,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BjE;AAED,uOAAuO;AACvO,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,EAAE,EAC/B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,oBAAoB,GAAG,SAAS,CASlC"}
|
|
@@ -27,6 +27,24 @@
|
|
|
27
27
|
* straightforward digest comparison over this ledger — never a guess through
|
|
28
28
|
* CI logs.
|
|
29
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* The id space a `ReleaseRecord.runId` lives in, and how to reach the run
|
|
32
|
+
* (#2045).
|
|
33
|
+
*/
|
|
34
|
+
export interface RunOrigin {
|
|
35
|
+
/**
|
|
36
|
+
* Which id space minted `runId`: `github` (a GitHub Actions run id — also
|
|
37
|
+
* the spelling Forgejo Actions uses, since it implements the same env
|
|
38
|
+
* contract; `url` disambiguates the actual host), `gitlab` (a CI pipeline
|
|
39
|
+
* id), `op` (an orchestrator/Op run id), or `local` (minted on the machine
|
|
40
|
+
* that ran the deploy, resolvable nowhere).
|
|
41
|
+
*/
|
|
42
|
+
forge: "github" | "gitlab" | "op" | "local";
|
|
43
|
+
/** Repo/project slug on the forge (`GITHUB_REPOSITORY` / `CI_PROJECT_PATH`), when the environment named one. */
|
|
44
|
+
repo?: string;
|
|
45
|
+
/** Resolved link to the run, when the environment provided enough to build one. */
|
|
46
|
+
url?: string;
|
|
47
|
+
}
|
|
30
48
|
/**
|
|
31
49
|
* One immutable deploy record: `(component, env, artifact digest, git sha,
|
|
32
50
|
* run id, timestamp, actor)`, referencing the build archive by digest — the
|
|
@@ -50,8 +68,19 @@ export interface ReleaseRecord {
|
|
|
50
68
|
digest: string;
|
|
51
69
|
/** Git commit SHA the deploy was built from. */
|
|
52
70
|
gitSha: string;
|
|
53
|
-
/** Orchestrator run identifier (a `DriverRunResult`/Op run id, or a CI run id in generate mode) — the pointer back into the deploy event log. */
|
|
71
|
+
/** Orchestrator run identifier (a `DriverRunResult`/Op run id, or a CI run id in generate mode) — the pointer back into the deploy event log. Which id space it lives in, and how to follow it, is `runOrigin`'s job (#2045). */
|
|
54
72
|
runId: string;
|
|
73
|
+
/**
|
|
74
|
+
* Where `runId` can be resolved (#2045). A bare `runId` names a run in one
|
|
75
|
+
* of several mutually incompatible id spaces — a GitHub Actions run id, a
|
|
76
|
+
* GitLab pipeline id, an Op run id, a locally minted id — and without this
|
|
77
|
+
* a reader can tell them apart only by inference from whoever wrote the
|
|
78
|
+
* record. Written at record time from the same environment the id came
|
|
79
|
+
* from, so the two cannot skew. Optional: records written before this
|
|
80
|
+
* field existed, and callers passing an id whose origin they did not
|
|
81
|
+
* declare, simply have none.
|
|
82
|
+
*/
|
|
83
|
+
runOrigin?: RunOrigin;
|
|
55
84
|
/**
|
|
56
85
|
* When this record was written. The caller supplies this — the session
|
|
57
86
|
* cannot call `Date.now()` reliably in every context, so the CLI resolves
|
|
@@ -104,6 +133,31 @@ export declare class InvalidReleaseRecordError extends Error {
|
|
|
104
133
|
export declare function validateReleaseRecord(record: Partial<ReleaseRecord>): string[];
|
|
105
134
|
/** Input a caller supplies to record one deploy — `version` is filled in, everything else is required (see `ReleaseRecord`). */
|
|
106
135
|
export type ReleaseRecordInput = Omit<ReleaseRecord, "version">;
|
|
136
|
+
/**
|
|
137
|
+
* Resolve a run id and its origin from the same environment, in one step, so
|
|
138
|
+
* the two cannot skew (#2045). Resolution order mirrors what
|
|
139
|
+
* `chant components release` always did — explicit id, then
|
|
140
|
+
* `GITHUB_RUN_ID`, then `CI_PIPELINE_ID`, then a locally minted
|
|
141
|
+
* `local-<ms>` — but now each source also names its id space:
|
|
142
|
+
*
|
|
143
|
+
* - the GitHub path records `repo` (`GITHUB_REPOSITORY`) and builds the run
|
|
144
|
+
* `url` from `GITHUB_SERVER_URL` — which also makes a Forgejo instance's
|
|
145
|
+
* runs resolvable, since Forgejo Actions implements the same env contract;
|
|
146
|
+
* - the GitLab path records `repo` (`CI_PROJECT_PATH`) and takes
|
|
147
|
+
* `CI_PIPELINE_URL` verbatim;
|
|
148
|
+
* - the local mint says `local` in a field instead of only in the id's
|
|
149
|
+
* spelling.
|
|
150
|
+
*
|
|
151
|
+
* An explicit id still gets an origin when it matches the id the environment
|
|
152
|
+
* itself is advertising (a CI job passing `--run-id $GITHUB_RUN_ID`);
|
|
153
|
+
* otherwise the caller's id is recorded without one — guessing an origin the
|
|
154
|
+
* caller did not state would be exactly the inference this field exists to
|
|
155
|
+
* remove.
|
|
156
|
+
*/
|
|
157
|
+
export declare function resolveRunId(explicit?: string, env?: NodeJS.ProcessEnv): {
|
|
158
|
+
runId: string;
|
|
159
|
+
runOrigin?: RunOrigin;
|
|
160
|
+
};
|
|
107
161
|
/**
|
|
108
162
|
* Append one immutable release record to the `<env>` ledger on the
|
|
109
163
|
* `chant/lifecycle` orphan branch. Throws `InvalidReleaseRecordError` before
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/release-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,OAAO,EAAE,CAAC,CAAC;IACX,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,
|
|
1
|
+
{"version":3,"file":"release-ledger.d.ts","sourceRoot":"","sources":["../../src/lifecycle/release-ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;OAMG;IACH,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC;IAC5C,gHAAgH;IAChH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,4FAA4F;IAC5F,OAAO,EAAE,CAAC,CAAC;IACX,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,iOAAiO;IACjO,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gOAAgO;IAChO,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAaD,4KAA4K;AAC5K,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,OAAO,EAAE,MAAM,EAAE;gBAAjB,OAAO,EAAE,MAAM,EAAE;CAI9C;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM,EAAE,CAO9E;AAED,gIAAgI;AAChI,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,CAAC,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAE,CAsB1C;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,kBAAkB,EACzB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,CAQpD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB1D;AAED,4EAA4E;AAC5E,wBAAsB,uBAAuB,CAAC,IAAI,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAExF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CASvF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE,CAE1F"}
|
|
@@ -64,9 +64,23 @@ export interface ActivityContract<Args = unknown, Return = unknown> {
|
|
|
64
64
|
* per #1290 — a later step's reference into this one's output.
|
|
65
65
|
*/
|
|
66
66
|
returns?: z.ZodType<Return>;
|
|
67
|
+
/**
|
|
68
|
+
* Names of top-level args whose values identify what the activity's effect
|
|
69
|
+
* touches in the estate (#2022) — an entity id, a resource address, a
|
|
70
|
+
* target endpoint — as opposed to scope (`env`, a stack name) or mechanics
|
|
71
|
+
* (a timeout, a mode). op.json's IR resolves these per step into
|
|
72
|
+
* `OpIRActivityStep.entities`, so a renderer can join a step to the estate
|
|
73
|
+
* nodes it touches instead of inventing joins off scope fields. Optional
|
|
74
|
+
* and partial by design, like the contract itself: an activity whose
|
|
75
|
+
* touched set is not spelled in its args (e.g. an applier that derives
|
|
76
|
+
* stack members internally) simply declares none.
|
|
77
|
+
*/
|
|
78
|
+
entities?: string[];
|
|
67
79
|
}
|
|
68
80
|
/** Declare an activity contract. */
|
|
69
|
-
export declare function activityContract<ArgsSchema extends z.ZodTypeAny, ReturnSchema extends z.ZodTypeAny = never>(name: string, args: ArgsSchema, returns?: ReturnSchema
|
|
81
|
+
export declare function activityContract<ArgsSchema extends z.ZodTypeAny, ReturnSchema extends z.ZodTypeAny = never>(name: string, args: ArgsSchema, returns?: ReturnSchema, opts?: {
|
|
82
|
+
entities?: string[];
|
|
83
|
+
}): ActivityContract<z.infer<ArgsSchema>, ReturnSchema extends z.ZodTypeAny ? z.infer<ReturnSchema> : unknown>;
|
|
70
84
|
/** Structural guard for a value produced by {@link activityContract}. */
|
|
71
85
|
export declare function isActivityContract(value: unknown): value is ActivityContract;
|
|
72
86
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activity-contract.d.ts","sourceRoot":"","sources":["../../src/op/activity-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAiD,MAAM,SAAS,CAAC;AAEvF,2HAA2H;AAC3H,eAAO,MAAM,uBAAuB,6FAO1B,CAAC;AAEX,QAAA,MAAM,cAAc,eAA0C,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO;IAChE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC;IAChC,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"activity-contract.d.ts","sourceRoot":"","sources":["../../src/op/activity-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAiD,MAAM,SAAS,CAAC;AAEvF,2HAA2H;AAC3H,eAAO,MAAM,uBAAuB,6FAO1B,CAAC;AAEX,QAAA,MAAM,cAAc,eAA0C,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO;IAChE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC;IAChC,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,oCAAoC;AACpC,wBAAgB,gBAAgB,CAAC,UAAU,SAAS,CAAC,CAAC,UAAU,EAAE,YAAY,SAAS,CAAC,CAAC,UAAU,GAAG,KAAK,EACzG,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,YAAY,EACtB,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7B,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,YAAY,SAAS,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,CAQ5G;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,IAAI,CAIhH;AAID,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,GAAG,SAAS,CASxG;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvF,wBAAgB,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,GAAG,mBAAmB,GAAG,SAAS,CAQrF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,WAAW,CAAC,EACvD,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAC/C,qBAAqB,EAAE,CA+CzB"}
|
|
@@ -10,8 +10,16 @@
|
|
|
10
10
|
import type { CarveReport } from "./carve.js";
|
|
11
11
|
import type { OwnershipMarker } from "../ownership.js";
|
|
12
12
|
export declare const CARVE_MANIFEST_SUFFIX = ".carve.json";
|
|
13
|
+
/**
|
|
14
|
+
* Version 2 (#2039): `emit.files`, `bridge.written`, `bridge.patch` and
|
|
15
|
+
* `apply.stampedFiles` are recorded relative to the manifest's own directory,
|
|
16
|
+
* so the manifest stays true when the tree is copied, moved, or checked out
|
|
17
|
+
* elsewhere. Version-1 manifests recorded them absolute; readers resolve
|
|
18
|
+
* either through `resolveManifestFilePath`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const CARVE_MANIFEST_VERSION = 2;
|
|
13
21
|
export interface CarveManifest {
|
|
14
|
-
version: 1;
|
|
22
|
+
version: 1 | 2;
|
|
15
23
|
/** Terraform address of the carved resource, e.g. `aws_s3_bucket.assets`. */
|
|
16
24
|
target: string;
|
|
17
25
|
/** Terraform resource type, when known. */
|
|
@@ -25,7 +33,13 @@ export interface CarveManifest {
|
|
|
25
33
|
/** Recorded by `carve emit`. */
|
|
26
34
|
emit?: {
|
|
27
35
|
source: "tfstate" | "live";
|
|
28
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Emitted chant source file path(s), relative to the manifest's directory
|
|
38
|
+
* (absolute in version-1 manifests). The manifest sits at the scaffolded
|
|
39
|
+
* project's root, so these are also project-root-relative — the same base
|
|
40
|
+
* `chant graph --format ir` uses for `sourceLoc.file`, which is the join
|
|
41
|
+
* from a carved Terraform address to the chant entity it became (#2040).
|
|
42
|
+
*/
|
|
29
43
|
files: string[];
|
|
30
44
|
/**
|
|
31
45
|
* Deferred outbound inputs declared as build parameters in the emitted
|
|
@@ -45,9 +59,10 @@ export interface CarveManifest {
|
|
|
45
59
|
};
|
|
46
60
|
/** Recorded by `carve bridge`. */
|
|
47
61
|
bridge?: {
|
|
62
|
+
/** Files written, relative to the manifest's directory (absolute in version-1 manifests). */
|
|
48
63
|
written: string[];
|
|
49
64
|
appliedInPlace: boolean;
|
|
50
|
-
/** The git-applyable `.patch` carrying the whole survivor edit. */
|
|
65
|
+
/** The git-applyable `.patch` carrying the whole survivor edit, relative to the manifest's directory (absolute in version-1 manifests). */
|
|
51
66
|
patch?: string;
|
|
52
67
|
/** Carved addresses whose own `.tf` block the rewrites remove (#998). */
|
|
53
68
|
excised?: string[];
|
|
@@ -57,7 +72,7 @@ export interface CarveManifest {
|
|
|
57
72
|
apply?: {
|
|
58
73
|
marker: OwnershipMarker;
|
|
59
74
|
ownershipTags: Record<string, string>;
|
|
60
|
-
/** Emitted files the marker was stamped into (`--write-source`). */
|
|
75
|
+
/** Emitted files the marker was stamped into (`--write-source`), relative to the manifest's directory (absolute in version-1 manifests). */
|
|
61
76
|
stampedFiles?: string[];
|
|
62
77
|
at: string;
|
|
63
78
|
};
|
|
@@ -66,9 +81,15 @@ export interface CarveManifest {
|
|
|
66
81
|
export declare function carveSlug(target: string): string;
|
|
67
82
|
/** Where the manifest for `target` lives inside an output dir. */
|
|
68
83
|
export declare function carveManifestPath(outDir: string, target: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* Resolve a manifest-recorded file path against the manifest's directory.
|
|
86
|
+
* Absolute paths (version-1 manifests) pass through untouched, so both
|
|
87
|
+
* on-disk spellings read the same.
|
|
88
|
+
*/
|
|
89
|
+
export declare function resolveManifestFilePath(manifestDir: string, p: string): string;
|
|
69
90
|
/** Write (or overwrite) a manifest into the output dir. Returns the path. */
|
|
70
91
|
export declare function writeCarveManifest(outDir: string, manifest: CarveManifest): string;
|
|
71
|
-
/** Read a manifest, or null when absent/unreadable/not a
|
|
92
|
+
/** Read a manifest, or null when absent/unreadable/not a known-version manifest. */
|
|
72
93
|
export declare function readCarveManifest(path: string): CarveManifest | null;
|
|
73
94
|
/** All carve manifest paths in an output dir. */
|
|
74
95
|
export declare function listCarveManifests(outDir: string): string[];
|
|
@@ -84,6 +105,10 @@ export interface ResolvedManifest {
|
|
|
84
105
|
* several is an error naming what is (or is not) there.
|
|
85
106
|
*/
|
|
86
107
|
export declare function resolveCarveManifest(outDir: string, select?: string): ResolvedManifest;
|
|
87
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Read-modify-write a section of an existing manifest. No-op when absent.
|
|
110
|
+
* The whole manifest is re-normalized on write, so updating a version-1
|
|
111
|
+
* manifest also migrates its recorded paths to the relative contract.
|
|
112
|
+
*/
|
|
88
113
|
export declare function updateCarveManifest(outDir: string, target: string, patch: Partial<Pick<CarveManifest, "boundary" | "emit" | "bridge" | "apply">>): string | undefined;
|
|
89
114
|
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/terraform/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/terraform/manifest.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/audit/catalog.ts
CHANGED
|
@@ -127,6 +127,22 @@ export const CF_STATIC_ASSETS: Authority = {
|
|
|
127
127
|
name: "Cloudflare Workers — Static assets",
|
|
128
128
|
url: "https://developers.cloudflare.com/workers/static-assets/",
|
|
129
129
|
};
|
|
130
|
+
export const MOZILLA_TLS: Authority = {
|
|
131
|
+
name: "Mozilla — Server Side TLS",
|
|
132
|
+
url: "https://wiki.mozilla.org/Security/Server_Side_TLS",
|
|
133
|
+
};
|
|
134
|
+
export const CWE_DIR_LISTING: Authority = {
|
|
135
|
+
name: "CWE-548 — Exposure of Information Through Directory Listing",
|
|
136
|
+
url: "https://cwe.mitre.org/data/definitions/548.html",
|
|
137
|
+
};
|
|
138
|
+
export const GIXY_ALIAS: Authority = {
|
|
139
|
+
name: "Gixy — alias traversal",
|
|
140
|
+
url: "https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md",
|
|
141
|
+
};
|
|
142
|
+
export const NGINX_STUB_STATUS: Authority = {
|
|
143
|
+
name: "nginx — ngx_http_stub_status_module",
|
|
144
|
+
url: "https://nginx.org/en/docs/http/ngx_http_stub_status_module.html",
|
|
145
|
+
};
|
|
130
146
|
export const CWE_HARDCODED_CREDS: Authority = {
|
|
131
147
|
name: "CWE-798 — Use of Hard-coded Credentials",
|
|
132
148
|
url: "https://cwe.mitre.org/data/definitions/798.html",
|
|
@@ -197,6 +213,14 @@ export const RULE_CATEGORY: Record<string, Category> = {
|
|
|
197
213
|
WRG004: "security",
|
|
198
214
|
WRG005: "security",
|
|
199
215
|
WRG006: "security",
|
|
216
|
+
// NGX — nginx config audit (#1979), lexicon-independent like SEC/WRG.
|
|
217
|
+
NGX001: "security",
|
|
218
|
+
NGX002: "security",
|
|
219
|
+
NGX003: "security",
|
|
220
|
+
NGX004: "security",
|
|
221
|
+
NGX005: "security",
|
|
222
|
+
NGX006: "best-practice",
|
|
223
|
+
NGX007: "best-practice",
|
|
200
224
|
// AGT — agent configuration (`chant audit --agents`). Core-owned like COR/EXT:
|
|
201
225
|
// these run against the machine's own agent config, not against any one
|
|
202
226
|
// lexicon's emitted output, so no lexicon ships them.
|
|
@@ -247,6 +271,17 @@ export const RULE_CATALOG: Record<string, RuleMeta> = {
|
|
|
247
271
|
WRG005: meta("WRG005", M, G, "Non-production environment shares a data store with production", "Give the non-production environment its own KV namespace/R2 bucket/D1 database id instead of reusing production's.", [CF_ENVIRONMENTS]),
|
|
248
272
|
WRG006: meta("WRG006", M, G, "Static assets served from the project root", "Point [site].bucket / [assets].directory at a dedicated public output folder, not the project root, so non-public files (config, source maps, .git) aren't served.", [CF_STATIC_ASSETS]),
|
|
249
273
|
|
|
274
|
+
// nginx config audit (#1979, the #446 follow-up) — lexicon-independent,
|
|
275
|
+
// same shape as SEC/WRG: `nginx.ts` scans every nginx config it detects
|
|
276
|
+
// regardless of which (if any) audit lexicons are installed.
|
|
277
|
+
NGX001: meta("NGX001", M, G, "Deprecated TLS protocol enabled", "Remove SSLv2/SSLv3/TLSv1/TLSv1.1 from ssl_protocols and serve TLSv1.2 and TLSv1.3 only.", [MOZILLA_TLS]),
|
|
278
|
+
NGX002: meta("NGX002", M, G, "Weak cipher suite enabled", "Remove the RC4/DES/MD5/NULL/EXPORT-class entries from ssl_ciphers and use a modern cipher list (e.g. Mozilla's intermediate configuration).", [MOZILLA_TLS]),
|
|
279
|
+
NGX003: meta("NGX003", M, G, "Directory listing enabled", "Remove `autoindex on` (or scope it to a directory that is genuinely meant to be enumerated) so file listings aren't served to anyone who asks.", [CWE_DIR_LISTING]),
|
|
280
|
+
NGX004: meta("NGX004", M, G, "alias path traversal", "End the location prefix with \"/\" so it matches the trailing slash of the alias target — without it, a request for \"<prefix>../\" escapes the aliased directory.", [GIXY_ALIAS]),
|
|
281
|
+
NGX005: meta("NGX005", M, G, "Status endpoint with no access restriction", "Restrict the stub_status location with allow/deny (or auth_basic/auth_request) so connection metrics aren't public reconnaissance.", [NGINX_STUB_STATUS]),
|
|
282
|
+
NGX006: meta("NGX006", R, G, "Server version disclosure", "Add `server_tokens off;` in the http block so nginx stops advertising its exact version in the Server header and error pages."),
|
|
283
|
+
NGX007: meta("NGX007", R, G, "Access logging disabled at server scope", "Re-enable access_log at http/server scope (silencing a single noisy location is fine) so requests are recorded for incident investigation."),
|
|
284
|
+
|
|
250
285
|
// ── Agent configuration (`chant audit --agents`) ──────────────────
|
|
251
286
|
AGT001: agentMeta(
|
|
252
287
|
"AGT001",
|
|
@@ -54,8 +54,8 @@ function resolveRelative(from: string, spec: string): string | undefined {
|
|
|
54
54
|
return undefined;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/** Static (non-type-only)
|
|
58
|
-
function
|
|
57
|
+
/** Static (non-type-only) import/re-export specifiers of a file. */
|
|
58
|
+
function staticSpecifiers(sf: ts.SourceFile): string[] {
|
|
59
59
|
const out: string[] = [];
|
|
60
60
|
for (const stmt of sf.statements) {
|
|
61
61
|
let spec: string | undefined;
|
|
@@ -66,7 +66,16 @@ function staticImports(sf: ts.SourceFile): string[] {
|
|
|
66
66
|
if (stmt.isTypeOnly) continue;
|
|
67
67
|
spec = (stmt.moduleSpecifier as ts.StringLiteral).text;
|
|
68
68
|
}
|
|
69
|
-
if (
|
|
69
|
+
if (spec) out.push(spec);
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Static (non-type-only) imports and re-exports of a file, resolved to paths. */
|
|
75
|
+
function staticImports(sf: ts.SourceFile): string[] {
|
|
76
|
+
const out: string[] = [];
|
|
77
|
+
for (const spec of staticSpecifiers(sf)) {
|
|
78
|
+
if (!spec.startsWith(".")) continue;
|
|
70
79
|
const resolved = resolveRelative(sf.fileName, spec);
|
|
71
80
|
if (resolved) out.push(resolved);
|
|
72
81
|
}
|
|
@@ -171,4 +180,28 @@ describe("edge-imported lexicon modules are init-safe", () => {
|
|
|
171
180
|
for (const sf of transitiveClosure(barrels()).values()) offenders.push(...moduleScopeOffenses(sf));
|
|
172
181
|
expect(offenders, "move these into a function (lazy) — they crash edge bundles").toEqual([]);
|
|
173
182
|
});
|
|
183
|
+
|
|
184
|
+
test("no static import of the full @intentius/chant barrel in the transitive import graph", () => {
|
|
185
|
+
// The relative-import walk above stops at package specifiers, and the bare
|
|
186
|
+
// core barrel is exactly the package import that must never appear: its
|
|
187
|
+
// static graph reaches build() → discovery/fold-import → the TypeScript
|
|
188
|
+
// compiler, whose own module init touches __filename and crashes workerd
|
|
189
|
+
// at startup. This is how WHM503's `../../render` import (whose render.ts
|
|
190
|
+
// imports `@intentius/chant` for Composite) broke the hosted audit's
|
|
191
|
+
// 0.53.1 bump. Subpath imports (`@intentius/chant/lint/post-synth`,
|
|
192
|
+
// `@intentius/chant/effect-receipt`, …) are the deliberately edge-clean
|
|
193
|
+
// seams and stay allowed.
|
|
194
|
+
const offenders: string[] = [];
|
|
195
|
+
for (const sf of transitiveClosure(barrels()).values()) {
|
|
196
|
+
for (const spec of staticSpecifiers(sf)) {
|
|
197
|
+
if (spec === "@intentius/chant") {
|
|
198
|
+
offenders.push(sf.fileName.replace(lexiconsDir, "lexicons"));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
expect(
|
|
203
|
+
offenders,
|
|
204
|
+
"these edge-reachable modules import the full core barrel — import the specific subpath (or split the needed piece into a light module) instead",
|
|
205
|
+
).toEqual([]);
|
|
206
|
+
});
|
|
174
207
|
});
|