@intentius/chant 0.122.0 → 0.124.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/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/handlers/gate-resume.d.ts +1 -1
- package/dist/cli/handlers/gate-resume.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +1 -1
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/override-approve.d.ts +17 -0
- package/dist/cli/handlers/override-approve.d.ts.map +1 -0
- package/dist/cli/handlers/run-wave.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +4 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/config-import.d.ts +1 -1
- package/dist/gate-decision.d.ts +157 -0
- package/dist/gate-decision.d.ts.map +1 -0
- package/dist/lifecycle/gate-applied.d.ts +75 -0
- package/dist/lifecycle/gate-applied.d.ts.map +1 -0
- package/dist/lifecycle/gate-audit.d.ts +145 -0
- package/dist/lifecycle/gate-audit.d.ts.map +1 -0
- package/dist/lifecycle/gate-ledger-select.d.ts +54 -0
- package/dist/lifecycle/gate-ledger-select.d.ts.map +1 -0
- package/dist/lifecycle/gate-ledger.d.ts +1 -45
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/override-ledger.d.ts +34 -0
- package/dist/lifecycle/override-ledger.d.ts.map +1 -0
- package/dist/lifecycle/rollback.d.ts.map +1 -1
- package/dist/lifecycle/work-item-id.d.ts +22 -0
- package/dist/lifecycle/work-item-id.d.ts.map +1 -0
- package/dist/lifecycle/work-lease.d.ts +2 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/post-synth.d.ts +20 -1
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/notify-verify.d.ts +62 -0
- package/dist/notify-verify.d.ts.map +1 -0
- package/dist/notify-verify.js +76 -0
- package/dist/notify.d.ts +202 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +307 -0
- package/dist/op/__fixtures__/decide-stub-backend.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +4 -4
- package/dist/op/activities/gh-host.d.ts +37 -0
- package/dist/op/activities/gh-host.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +11 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activities/propose-upgrade.d.ts.map +1 -1
- package/dist/op/activities/reconcile.d.ts +74 -76
- package/dist/op/activities/reconcile.d.ts.map +1 -1
- package/dist/op/gate-approval.d.ts +17 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +8 -1
- package/dist/op/gate-name.d.ts.map +1 -1
- package/dist/op/gate-resume.d.ts +4 -2
- package/dist/op/gate-resume.d.ts.map +1 -1
- package/dist/op/gate-review.d.ts +2 -1
- package/dist/op/gate-review.d.ts.map +1 -1
- package/dist/op/gate.d.ts +43 -6
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +8 -6
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/op-waves-notify.d.ts +31 -0
- package/dist/op/op-waves-notify.d.ts.map +1 -0
- package/dist/op/op-waves-run.d.ts +218 -16
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves.d.ts +113 -2
- package/dist/op/op-waves.d.ts.map +1 -1
- package/dist/op/operator.d.ts +15 -0
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/work-lease-decl.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/override-gate.d.ts +224 -0
- package/dist/override-gate.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +225 -19
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +1 -1
- package/dist/workspace/conformance/broker.d.ts +1 -1
- package/dist/workspace/status-gates.d.ts +1 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/trust/gate-seal.d.ts +96 -0
- package/dist/workspace/trust/gate-seal.d.ts.map +1 -0
- package/dist/workspace/trust/policy.d.ts +2 -41
- package/dist/workspace/trust/policy.d.ts.map +1 -1
- package/dist/workspace/trust/seal.d.ts +2 -27
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/trust-files.d.ts +57 -0
- package/dist/workspace/trust/trust-files.d.ts.map +1 -0
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/package.json +15 -2
- package/src/cli/commands/build.ts +1 -1
- package/src/cli/commands/check-lexicon.ts +3 -1
- package/src/cli/commands/lint-post-synth.e2e.test.ts +117 -0
- package/src/cli/commands/lint.test.ts +4 -109
- package/src/cli/commands/lint.ts +5 -2
- package/src/cli/discovery-skip.e2e.test.ts +18 -3
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/gate-resume.ts +3 -2
- package/src/cli/handlers/operator.test.ts +12 -1
- package/src/cli/handlers/operator.ts +25 -13
- package/src/cli/handlers/override-approve.test.ts +87 -0
- package/src/cli/handlers/override-approve.ts +103 -0
- package/src/cli/handlers/run-wave.ts +10 -2
- package/src/cli/main.test.ts +8 -0
- package/src/cli/main.ts +15 -0
- package/src/cli/registry.ts +4 -0
- package/src/config-import.ts +1 -1
- package/src/discovery/sandbox/run.test.ts +1 -1
- package/src/gate-decision-bundle.test.ts +56 -0
- package/src/gate-decision.test.ts +237 -0
- package/src/gate-decision.ts +321 -0
- package/src/lifecycle/gate-applied.ts +115 -0
- package/src/lifecycle/gate-audit-bundle.test.ts +47 -0
- package/src/lifecycle/gate-audit.test.ts +134 -0
- package/src/lifecycle/gate-audit.ts +438 -0
- package/src/lifecycle/gate-ledger-select.ts +113 -0
- package/src/lifecycle/gate-ledger.test.ts +22 -0
- package/src/lifecycle/gate-ledger.ts +9 -104
- package/src/lifecycle/override-ledger.test.ts +63 -0
- package/src/lifecycle/override-ledger.ts +69 -0
- package/src/lifecycle/rollback.ts +5 -1
- package/src/lifecycle/work-item-id.test.ts +71 -0
- package/src/lifecycle/work-item-id.ts +35 -0
- package/src/lifecycle/work-lease.ts +4 -5
- package/src/lint/policy-import.ts +1 -1
- package/src/lint/post-synth.test.ts +29 -0
- package/src/lint/post-synth.ts +21 -2
- package/src/notify-bundle.test.ts +50 -0
- package/src/notify-plain-node.e2e.test.ts +68 -0
- package/src/notify-verify.test.ts +59 -0
- package/src/notify-verify.ts +93 -0
- package/src/notify.schema.json +72 -0
- package/src/notify.test.ts +279 -0
- package/src/notify.ts +398 -0
- package/src/op/__fixtures__/decide-stub-backend.ts +1 -1
- package/src/op/activities/gh-host.test.ts +130 -0
- package/src/op/activities/gh-host.ts +79 -0
- package/src/op/activities/lexicon-upgrade.ts +22 -1
- package/src/op/activities/propose-upgrade.ts +5 -1
- package/src/op/activities/reconcile.test.ts +284 -280
- package/src/op/activities/reconcile.ts +128 -131
- package/src/op/gate-approval.test.ts +175 -7
- package/src/op/gate-approval.ts +27 -1
- package/src/op/gate-name.ts +10 -2
- package/src/op/gate-resume.ts +6 -3
- package/src/op/gate-review.ts +4 -7
- package/src/op/gate.ts +117 -16
- package/src/op/index.ts +36 -5
- package/src/op/op-waves-notify.test.ts +127 -0
- package/src/op/op-waves-notify.ts +101 -0
- package/src/op/op-waves-run.ts +908 -123
- package/src/op/op-waves.test.ts +543 -3
- package/src/op/op-waves.ts +215 -6
- package/src/op/operator.test.ts +29 -0
- package/src/op/operator.ts +27 -2
- package/src/op/run-context.test.ts +2 -2
- package/src/op/work-lease-decl.ts +4 -4
- package/src/op/work-lease-run.test.ts +5 -0
- package/src/op/work-lease-run.ts +4 -3
- package/src/override-gate-bundle.test.ts +47 -0
- package/src/override-gate.test.ts +239 -0
- package/src/override-gate.ts +395 -0
- package/src/pr-forge-bundle.test.ts +40 -0
- package/src/pr-forge.test.ts +378 -0
- package/src/pr-forge.ts +546 -47
- package/src/workspace/conformance/__fixture__/decisions/decision.kind.mjs +1 -1
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +1 -1
- package/src/workspace/conformance/broker.ts +1 -1
- package/src/workspace/records-write-contract.test.ts +3 -2
- package/src/workspace/records-write.e2e.test.ts +1 -1
- package/src/workspace/status-gates.ts +7 -4
- package/src/workspace/trust/gate-seal.test.ts +156 -0
- package/src/workspace/trust/gate-seal.ts +254 -0
- package/src/workspace/trust/policy.ts +10 -165
- package/src/workspace/trust/seal.ts +19 -34
- package/src/workspace/trust/trust-files.test.ts +50 -0
- package/src/workspace/trust/trust-files.ts +245 -0
- package/src/workspace/work-cli.ts +5 -3
- package/src/workspace/work-history.test.ts +7 -0
- /package/src/audit/{catalog.test.ts → catalog.e2e.test.ts} +0 -0
- /package/src/audit/{discover.test.ts → discover.e2e.test.ts} +0 -0
- /package/src/audit/{remote-discovery.test.ts → remote-discovery.e2e.test.ts} +0 -0
- /package/src/audit/{rules-doc.test.ts → rules-doc.e2e.test.ts} +0 -0
- /package/src/{bench.test.ts → bench.e2e.test.ts} +0 -0
- /package/src/cli/commands/{check-lexicon-doc-drift.test.ts → check-lexicon-doc-drift.e2e.test.ts} +0 -0
- /package/src/cli/commands/{import.test.ts → import.e2e.test.ts} +0 -0
- /package/src/cli/{component-security-boundary.test.ts → component-security-boundary.e2e.test.ts} +0 -0
- /package/src/cli/mcp/{workspace-tools.test.ts → workspace-tools.e2e.test.ts} +0 -0
- /package/src/cli/{security-boundary.test.ts → security-boundary.e2e.test.ts} +0 -0
- /package/src/cli/{serve-mcp-workspace.test.ts → serve-mcp-workspace.e2e.test.ts} +0 -0
- /package/src/cli/{static-config-read.test.ts → static-config-read.e2e.test.ts} +0 -0
- /package/src/codegen/{json-schema-to-ts.test.ts → json-schema-to-ts.e2e.test.ts} +0 -0
- /package/src/{lexicon-seams.test.ts → lexicon-seams.e2e.test.ts} +0 -0
- /package/src/meta/{declared-imports.test.ts → declared-imports.e2e.test.ts} +0 -0
- /package/src/op/{command-gate.test.ts → command-gate.e2e.test.ts} +0 -0
- /package/src/op/{steward-beside.test.ts → steward-beside.e2e.test.ts} +0 -0
- /package/src/op/{steward-points.test.ts → steward-points.e2e.test.ts} +0 -0
- /package/src/workspace/{checks.test.ts → checks.e2e.test.ts} +0 -0
- /package/src/workspace/{intent-reviews.test.ts → intent-reviews.e2e.test.ts} +0 -0
- /package/src/workspace/{profiles.test.ts → profiles.e2e.test.ts} +0 -0
- /package/src/workspace/{read-contract.test.ts → read-contract.e2e.test.ts} +0 -0
- /package/src/workspace/{records-contract.test.ts → records-contract.e2e.test.ts} +0 -0
- /package/src/workspace/{records-since.test.ts → records-since.e2e.test.ts} +0 -0
- /package/src/workspace/{records-write.test.ts → records-write-commands.e2e.test.ts} +0 -0
- /package/src/workspace/{work-size.test.ts → work-size.e2e.test.ts} +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A gate approval's seal (#3163, ws-080), checked with node:crypto (#3763).
|
|
3
|
+
*
|
|
4
|
+
* `chant approve --sign` seals an approval with `ssh-keygen -Y sign` in the
|
|
5
|
+
* `chant-gate` namespace, over {@link gateSealPayload}. Signing shells to
|
|
6
|
+
* ssh-keygen; checking does not. This module checks a seal with node:crypto
|
|
7
|
+
* and no zod, and `checkGateSeal` (`./seal.ts`) and `sealedApprovalRule` use
|
|
8
|
+
* it, so an apply job needs no ssh-keygen. A tool that decides a gate from one bundled file
|
|
9
|
+
* (terragucci's apply job) runs the same rule: `@intentius/chant/gate-decision`
|
|
10
|
+
* exports it.
|
|
11
|
+
*
|
|
12
|
+
* An SSHSIG (OpenSSH's PROTOCOL.sshsig) holds the public key, the namespace,
|
|
13
|
+
* the hash algorithm and the signature over `"SSHSIG"`, the namespace, the
|
|
14
|
+
* reserved field, the algorithm and the message's hash. Ed25519, ECDSA (P-256,
|
|
15
|
+
* P-384, P-521), RSA with SHA-2, and the security-key forms of Ed25519 and
|
|
16
|
+
* P-256 verify, with the touch flag required, as ssh-keygen requires it for a
|
|
17
|
+
* signers line with no `no-touch-required` option (which the signers parser
|
|
18
|
+
* does not accept). An RSA signature over SHA-1 does not verify.
|
|
19
|
+
*/
|
|
20
|
+
import type { Signer } from "./trust-files.js";
|
|
21
|
+
/**
|
|
22
|
+
* The ssh signature namespace of a gate approval's seal (#3163, ws-080), so a
|
|
23
|
+
* verdict, record or commit signature can't stand in for one.
|
|
24
|
+
*/
|
|
25
|
+
export declare const GATE_SEAL_NAMESPACE = "chant-gate";
|
|
26
|
+
/** The gate approval a seal covers (#3163): the fields of a gate resolution line that say what was approved, by whom and when. */
|
|
27
|
+
export interface SealedGateApproval {
|
|
28
|
+
op: string;
|
|
29
|
+
gate: string;
|
|
30
|
+
environment?: string;
|
|
31
|
+
planDigest?: string;
|
|
32
|
+
resolvedBy: string;
|
|
33
|
+
/** Who relayed the approval for `resolvedBy` (#3402), when someone did. */
|
|
34
|
+
relayedBy?: string;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
seal?: unknown;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The bytes a gate approval's seal signs (#3163): the op (or component), the
|
|
40
|
+
* gate, the environment, the plan digest, the approver and the time, joined
|
|
41
|
+
* by LF with no final newline. An approval that binds no environment or plan
|
|
42
|
+
* signs an empty line for it. A relayed approval (#3402) signs a seventh line,
|
|
43
|
+
* `relayed-by <principal>`, so the relay can't be added, changed or removed
|
|
44
|
+
* after sealing; an approval nobody relayed signs the six lines it always did,
|
|
45
|
+
* so seals made before #3402 still verify.
|
|
46
|
+
*/
|
|
47
|
+
export declare function gateSealPayload(a: SealedGateApproval): Buffer;
|
|
48
|
+
/** `SHA256:<base64>`, the fingerprint ssh-keygen prints for a public key blob. */
|
|
49
|
+
export declare function sshKeyFingerprint(blob: Buffer): string;
|
|
50
|
+
/** What {@link verifySshSignatureWith} found. */
|
|
51
|
+
export type SshSignatureCheck = {
|
|
52
|
+
ok: true;
|
|
53
|
+
key: string;
|
|
54
|
+
} | {
|
|
55
|
+
ok: false;
|
|
56
|
+
reason: string;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Whether `armored`, an SSHSIG as `ssh-keygen -Y sign` writes it, signs
|
|
60
|
+
* `message` in `namespace` with one of `keys` (public key blobs, ssh wire
|
|
61
|
+
* format). Never throws. On success, `key` is the signing key's fingerprint.
|
|
62
|
+
*/
|
|
63
|
+
export declare function verifySshSignatureWith(armored: string, message: Buffer, namespace: string, keys: readonly Buffer[]): SshSignatureCheck;
|
|
64
|
+
/**
|
|
65
|
+
* The key blob an armored SSHSIG carries, or null when it is not one. For
|
|
66
|
+
* `ssh-keygen -Y check-novalidate`'s question, whether the signature is
|
|
67
|
+
* intact whoever's key it is: verify against this key.
|
|
68
|
+
*/
|
|
69
|
+
export declare function sshSignatureKey(armored: string): Buffer | null;
|
|
70
|
+
/**
|
|
71
|
+
* The signers a sealed gate is judged by, read at base. chant's own
|
|
72
|
+
* `TrustPolicy` (`./policy.ts`) is one; `gateSignersAt` in
|
|
73
|
+
* `@intentius/chant/gate-decision` reads one without zod.
|
|
74
|
+
*/
|
|
75
|
+
export interface GateSigners {
|
|
76
|
+
/** The commit the signers were read at, or null when there is no base. */
|
|
77
|
+
base: string | null;
|
|
78
|
+
/** The signers path used. */
|
|
79
|
+
signersPath: string;
|
|
80
|
+
/** Whether a signers file exists at base. False: no seal verifies, so a sealed gate passes nothing. */
|
|
81
|
+
active: boolean;
|
|
82
|
+
signers: Signer[];
|
|
83
|
+
/** Why the trust config could not be read, when it could not. `active` is false then. */
|
|
84
|
+
problems: string[];
|
|
85
|
+
}
|
|
86
|
+
/** Whether ssh-keygen's `namespaces="..."` pattern list admits `namespace`: a `*`/`?` pattern matches, and a `!` pattern that matches refuses. */
|
|
87
|
+
export declare function namespaceAllowed(list: string | undefined, namespace: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Why this approval does not count toward a sealed gate, or null when it
|
|
90
|
+
* does: its seal verifies, for the approver it names, against a key `signers`
|
|
91
|
+
* lists for that approver in the `chant-gate` namespace. With no signers file
|
|
92
|
+
* at base, nothing counts. The same rule as `sealedApprovalRule` in
|
|
93
|
+
* `../../op/gate-review.ts`, which checks with ssh-keygen.
|
|
94
|
+
*/
|
|
95
|
+
export declare function gateSealRefusal(signers: GateSigners, a: SealedGateApproval): string | null;
|
|
96
|
+
//# sourceMappingURL=gate-seal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-seal.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/gate-seal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD,kIAAkI;AAClI,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAG7D;AA8BD,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAmCD,iDAAiD;AACjD,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1F;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,iBAAiB,CA0CtI;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU9D;AAID;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,uGAAuG;IACvG,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAID,kJAAkJ;AAClJ,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAYrF;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,kBAAkB,GAAG,MAAM,GAAG,IAAI,CAmB1F"}
|
|
@@ -22,47 +22,8 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { z } from "zod";
|
|
24
24
|
import type { RecordSource } from "../record-source.js";
|
|
25
|
-
|
|
26
|
-
export
|
|
27
|
-
/** Where the signers are when `trust.json` names no other path. */
|
|
28
|
-
export declare const DEFAULT_SIGNERS_PATH = ".chant/allowed_signers";
|
|
29
|
-
/** One usable signer: a principal and the public key it signs with. */
|
|
30
|
-
export interface Signer {
|
|
31
|
-
principal: string;
|
|
32
|
-
/** `<type> <base64>`, with no comment. */
|
|
33
|
-
key: string;
|
|
34
|
-
/** The `namespaces="..."` option as written, or undefined when the key may sign any namespace. */
|
|
35
|
-
namespaces?: string;
|
|
36
|
-
/** 1-based line in the signers file. */
|
|
37
|
-
line: number;
|
|
38
|
-
}
|
|
39
|
-
/** A line of the signers file that is not used, and why. */
|
|
40
|
-
export interface ExcludedSigner {
|
|
41
|
-
line: number;
|
|
42
|
-
reason: string;
|
|
43
|
-
}
|
|
44
|
-
export interface SignerSet {
|
|
45
|
-
signers: Signer[];
|
|
46
|
-
excluded: ExcludedSigner[];
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Parse an allowed_signers file, keeping only lines whose meaning does not
|
|
50
|
-
* depend on anything the signer controls.
|
|
51
|
-
*
|
|
52
|
-
* Refused, each with a reason, rather than passed to ssh-keygen:
|
|
53
|
-
*
|
|
54
|
-
* - `valid-after` and `valid-before`. git checks them against the commit's own
|
|
55
|
-
* date, which whoever makes the commit sets. A backdated commit would pass a
|
|
56
|
-
* window its key has left. Revocation is by position in history (#2553),
|
|
57
|
-
* never by date.
|
|
58
|
-
* - `cert-authority`. A certificate's validity is also a date, and a CA key
|
|
59
|
-
* vouches for keys this file never names.
|
|
60
|
-
* - Principal patterns (`*`, `?`, `!`). A signer is named by one exact
|
|
61
|
-
* principal, so role grants can name it.
|
|
62
|
-
*/
|
|
63
|
-
export declare function parseAllowedSigners(text: string): SignerSet;
|
|
64
|
-
/** The signers as an allowed_signers file ssh-keygen reads, holding only the usable lines. */
|
|
65
|
-
export declare function renderAllowedSigners(signers: Signer[]): string;
|
|
25
|
+
import { type ExcludedSigner, type Signer } from "./trust-files.js";
|
|
26
|
+
export { DEFAULT_SIGNERS_PATH, TRUST_CONFIG_PATH, parseAllowedSigners, renderAllowedSigners, type ExcludedSigner, type Signer, type SignerSet, } from "./trust-files.js";
|
|
66
27
|
export declare const trustConfigSchema: z.ZodObject<{
|
|
67
28
|
schema: z.ZodLiteral<1>;
|
|
68
29
|
signers: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAgE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAE/H,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AAcvB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;kBA4DnB,CAAC;AAEZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,+FAA+F;AAC/F,eAAO,MAAM,UAAU,UAAU,CAAC;AAElC,kEAAkE;AAClE,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9C,qEAAqE;IACrE,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,iDAAiD;IACjD,eAAe,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,iHAAiH;IACjH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/E;AAED,0HAA0H;AAC1H,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,EAAE,CAG5D;AAED,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAI9D;AAED,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,GAAE,MAAM,EAAO,GAAG,WAAW,CAErF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,WAAW,CAiDtF;AAWD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAE3E;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKnF"}
|
|
@@ -23,15 +23,12 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import type { SealCode } from "../records.js";
|
|
25
25
|
import { type TrustPolicy } from "./policy.js";
|
|
26
|
+
import { type SealedGateApproval } from "./gate-seal.js";
|
|
27
|
+
export { GATE_SEAL_NAMESPACE, gateSealPayload, type SealedGateApproval } from "./gate-seal.js";
|
|
26
28
|
/** The ssh signature namespace of a verdict seal. */
|
|
27
29
|
export declare const REVIEW_SEAL_NAMESPACE = "chant-review";
|
|
28
30
|
/** The ssh signature namespace of a record's author seal (#2688). */
|
|
29
31
|
export declare const RECORD_SEAL_NAMESPACE = "chant-record";
|
|
30
|
-
/**
|
|
31
|
-
* The ssh signature namespace of a gate approval's seal (#3163, ws-080), so a
|
|
32
|
-
* verdict, record or commit signature can't stand in for one.
|
|
33
|
-
*/
|
|
34
|
-
export declare const GATE_SEAL_NAMESPACE = "chant-gate";
|
|
35
32
|
/** A seal as a review entry holds it. */
|
|
36
33
|
export interface VerdictSeal {
|
|
37
34
|
/** The principal who signed: the reviewer, as the signers file names them. */
|
|
@@ -68,28 +65,6 @@ export declare function reviewSealPayload(record: string, digest: string, verdic
|
|
|
68
65
|
* states signs an empty last line.
|
|
69
66
|
*/
|
|
70
67
|
export declare function recordSealPayload(record: string, digest: string, author: string, state: string | null): Buffer;
|
|
71
|
-
/** The gate approval a seal covers (#3163): the fields of a gate resolution line that say what was approved, by whom and when. */
|
|
72
|
-
export interface SealedGateApproval {
|
|
73
|
-
op: string;
|
|
74
|
-
gate: string;
|
|
75
|
-
environment?: string;
|
|
76
|
-
planDigest?: string;
|
|
77
|
-
resolvedBy: string;
|
|
78
|
-
/** Who relayed the approval for `resolvedBy` (#3402), when someone did. */
|
|
79
|
-
relayedBy?: string;
|
|
80
|
-
timestamp: string;
|
|
81
|
-
seal?: unknown;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* The bytes a gate approval's seal signs (#3163): the op (or component), the
|
|
85
|
-
* gate, the environment, the plan digest, the approver and the time, joined
|
|
86
|
-
* by LF with no final newline. An approval that binds no environment or plan
|
|
87
|
-
* signs an empty line for it. A relayed approval (#3402) signs a seventh line,
|
|
88
|
-
* `relayed-by <principal>`, so the relay can't be added, changed or removed
|
|
89
|
-
* after sealing; an approval nobody relayed signs the six lines it always did,
|
|
90
|
-
* so seals made before #3402 still verify.
|
|
91
|
-
*/
|
|
92
|
-
export declare function gateSealPayload(a: SealedGateApproval): Buffer;
|
|
93
68
|
/** The record an author seal covers (#2688). */
|
|
94
69
|
export interface SealedRecord {
|
|
95
70
|
record: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/seal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,
|
|
1
|
+
{"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/seal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trust files' plain readers (#3763): the signers file's parser, and a
|
|
3
|
+
* check of `.chant/trust.json` that says what `./policy.ts`'s zod schema
|
|
4
|
+
* says, so a bundle can read both without zod. `./policy.ts` re-exports the
|
|
5
|
+
* parser; `trust-files.test.ts` holds the check to the schema.
|
|
6
|
+
*/
|
|
7
|
+
/** The trust config, relative to the repository root. Fixed: it is how the signers path is overridden. */
|
|
8
|
+
export declare const TRUST_CONFIG_PATH = ".chant/trust.json";
|
|
9
|
+
/** Where the signers are when `trust.json` names no other path. */
|
|
10
|
+
export declare const DEFAULT_SIGNERS_PATH = ".chant/allowed_signers";
|
|
11
|
+
/** One usable signer: a principal and the public key it signs with. */
|
|
12
|
+
export interface Signer {
|
|
13
|
+
principal: string;
|
|
14
|
+
/** `<type> <base64>`, with no comment. */
|
|
15
|
+
key: string;
|
|
16
|
+
/** The `namespaces="..."` option as written, or undefined when the key may sign any namespace. */
|
|
17
|
+
namespaces?: string;
|
|
18
|
+
/** 1-based line in the signers file. */
|
|
19
|
+
line: number;
|
|
20
|
+
}
|
|
21
|
+
/** A line of the signers file that is not used, and why. */
|
|
22
|
+
export interface ExcludedSigner {
|
|
23
|
+
line: number;
|
|
24
|
+
reason: string;
|
|
25
|
+
}
|
|
26
|
+
export interface SignerSet {
|
|
27
|
+
signers: Signer[];
|
|
28
|
+
excluded: ExcludedSigner[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parse an allowed_signers file, keeping only lines whose meaning does not
|
|
32
|
+
* depend on anything the signer controls.
|
|
33
|
+
*
|
|
34
|
+
* Refused, each with a reason, rather than passed to ssh-keygen:
|
|
35
|
+
*
|
|
36
|
+
* - `valid-after` and `valid-before`. git checks them against the commit's own
|
|
37
|
+
* date, which whoever makes the commit sets. A backdated commit would pass a
|
|
38
|
+
* window its key has left. Revocation is by position in history (#2553),
|
|
39
|
+
* never by date.
|
|
40
|
+
* - `cert-authority`. A certificate's validity is also a date, and a CA key
|
|
41
|
+
* vouches for keys this file never names.
|
|
42
|
+
* - Principal patterns (`*`, `?`, `!`). A signer is named by one exact
|
|
43
|
+
* principal, so role grants can name it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseAllowedSigners(text: string): SignerSet;
|
|
46
|
+
/** The signers as an allowed_signers file ssh-keygen reads, holding only the usable lines. */
|
|
47
|
+
export declare function renderAllowedSigners(signers: Signer[]): string;
|
|
48
|
+
/** A repository-relative path: no `..`, not absolute, `/` separators. */
|
|
49
|
+
export declare function isRepoPath(p: unknown): p is string;
|
|
50
|
+
/**
|
|
51
|
+
* What is wrong with a parsed `.chant/trust.json`, one line per field, or an
|
|
52
|
+
* empty list when it is valid. It accepts exactly what `trustConfigSchema`
|
|
53
|
+
* in `./policy.ts` accepts, so a reader without zod treats a file as chant
|
|
54
|
+
* does: an invalid one turns attestation off.
|
|
55
|
+
*/
|
|
56
|
+
export declare function trustConfigProblems(raw: unknown): string[];
|
|
57
|
+
//# sourceMappingURL=trust-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-files.d.ts","sourceRoot":"","sources":["../../../src/workspace/trust/trust-files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,0GAA0G;AAC1G,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AAErD,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,2BAA2B,CAAC;AAe7D,uEAAuE;AACvE,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAmDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAkD3D;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAM9D;AASD,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAElD;AAOD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CA8C1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-cli.d.ts","sourceRoot":"","sources":["../../src/workspace/work-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,
|
|
1
|
+
{"version":3,"file":"work-cli.d.ts","sourceRoot":"","sources":["../../src/workspace/work-cli.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.124.0",
|
|
4
4
|
"description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"default": "./src/cli/index.ts"
|
|
51
51
|
},
|
|
52
52
|
"./workspace/*.schema.json": "./src/workspace/*.schema.json",
|
|
53
|
+
"./notify.schema.json": "./src/notify.schema.json",
|
|
53
54
|
"./workspace/factory-rules": {
|
|
54
55
|
"development": "./src/workspace/factory-rules.ts",
|
|
55
56
|
"types": "./dist/workspace/factory-rules.d.ts",
|
|
@@ -95,6 +96,18 @@
|
|
|
95
96
|
"types": "./dist/agents/index.d.ts",
|
|
96
97
|
"default": "./src/agents/index.ts"
|
|
97
98
|
},
|
|
99
|
+
"./notify-verify": {
|
|
100
|
+
"development": "./src/notify-verify.ts",
|
|
101
|
+
"types": "./dist/notify-verify.d.ts",
|
|
102
|
+
"import": "./dist/notify-verify.js",
|
|
103
|
+
"default": "./src/notify-verify.ts"
|
|
104
|
+
},
|
|
105
|
+
"./notify": {
|
|
106
|
+
"development": "./src/notify.ts",
|
|
107
|
+
"types": "./dist/notify.d.ts",
|
|
108
|
+
"import": "./dist/notify.js",
|
|
109
|
+
"default": "./src/notify.ts"
|
|
110
|
+
},
|
|
98
111
|
"./*": {
|
|
99
112
|
"development": "./src/*.ts",
|
|
100
113
|
"types": "./dist/*.d.ts",
|
|
@@ -102,7 +115,7 @@
|
|
|
102
115
|
}
|
|
103
116
|
},
|
|
104
117
|
"scripts": {
|
|
105
|
-
"build": "../../scripts/tsc7.sh -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete",
|
|
118
|
+
"build": "../../scripts/tsc7.sh -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) ! -path dist/notify.js ! -path dist/notify-verify.js -delete",
|
|
106
119
|
"prepack": "npm run build"
|
|
107
120
|
},
|
|
108
121
|
"dependencies": {
|
|
@@ -585,7 +585,7 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
|
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
if (result.errors.length === 0 && options.plugins) {
|
|
588
|
-
for (const { plugin, diagnostics: postDiags } of runLexiconPostSynthChecks(options.plugins, result, env, { activityContracts, telemetry })) {
|
|
588
|
+
for (const { plugin, diagnostics: postDiags } of runLexiconPostSynthChecks(options.plugins, result, env, { activityContracts, telemetry, projectDir: configDir, projectConfig: config as unknown as Record<string, unknown> })) {
|
|
589
589
|
// `lint.presets` (chant #2113) filters WHICH check ids are reported at
|
|
590
590
|
// all, before `lint.rules`/inline suppression act on the reported
|
|
591
591
|
// ones. It's a no-op for a lexicon that ships no `lintPresets()` (the
|
|
@@ -709,7 +709,9 @@ export async function checkLexicon(dir: string): Promise<CheckResult> {
|
|
|
709
709
|
pass: hasTypecheckTest,
|
|
710
710
|
});
|
|
711
711
|
|
|
712
|
-
|
|
712
|
+
// A round trip over a large corpus can be an end-to-end test, kept out of the unit project's
|
|
713
|
+
// per-test budget under the e2e name.
|
|
714
|
+
const hasRoundtripTest = findFiles(join(dir, "src"), (n) => n === "roundtrip.test.ts" || n === "roundtrip.e2e.test.ts").length > 0;
|
|
713
715
|
items.push({
|
|
714
716
|
name: "roundtrip.test.ts exists",
|
|
715
717
|
tier: 3,
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { lintCommand, BUILD_FAILURE_RULE_ID } from "./lint";
|
|
3
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { mkdtempSync, realpathSync, symlinkSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
// Each case builds a small project against the workspace's sql lexicon and runs its post-synth
|
|
10
|
+
// checks; the first loads the lexicon and took 3.1s on CI, near the unit project's 5s budget, so the
|
|
11
|
+
// block is an e2e file (#3793). The rest of lintCommand's tests are in lint.test.ts.
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* chant #3750 — `chant lint` runs each loaded lexicon's own post-synth checks
|
|
15
|
+
* over an in-memory build of the lint target, the ones `chant build` runs.
|
|
16
|
+
* The sql lexicon's SQLCH101 is the issue's repro: `ENGINE = MergeTre` failed
|
|
17
|
+
* the build and linted clean. The project imports the workspace's sql
|
|
18
|
+
* lexicon through a `node_modules` link, as an installed project would.
|
|
19
|
+
*/
|
|
20
|
+
describe("lintCommand — lexicon post-synth checks (#3750)", () => {
|
|
21
|
+
const repoNodeModules = resolve(fileURLToPath(new URL(".", import.meta.url)), "../../../../../node_modules");
|
|
22
|
+
let root: string;
|
|
23
|
+
|
|
24
|
+
const schema = (engine: string, idType = "UInt64") =>
|
|
25
|
+
'import { database, table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
|
|
26
|
+
"export const shopDb = database`CREATE DATABASE shop ENGINE = Atomic`;\n" +
|
|
27
|
+
"export const events = table`\n" +
|
|
28
|
+
` CREATE TABLE \${shopDb}.events (id ${idType}, kind String)\n` +
|
|
29
|
+
` ENGINE = ${engine}\n` +
|
|
30
|
+
" ORDER BY (kind, id)`;\n";
|
|
31
|
+
|
|
32
|
+
async function project(engine: string, rules?: Record<string, string>, idType?: string): Promise<void> {
|
|
33
|
+
await writeFile(
|
|
34
|
+
join(root, "chant.config.json"),
|
|
35
|
+
JSON.stringify({ lexicons: ["sql"], sql: { dialect: "clickhouse" }, ...(rules ? { lint: { rules } } : {}) }),
|
|
36
|
+
);
|
|
37
|
+
await writeFile(join(root, "src", "schema.ts"), schema(engine, idType));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
beforeEach(async () => {
|
|
41
|
+
root = realpathSync(mkdtempSync(join(tmpdir(), "chant-3750-")));
|
|
42
|
+
await mkdir(join(root, "src"), { recursive: true });
|
|
43
|
+
symlinkSync(repoNodeModules, join(root, "node_modules"), "dir");
|
|
44
|
+
process.env.NO_COLOR = "1";
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterEach(async () => {
|
|
48
|
+
await rm(root, { recursive: true, force: true });
|
|
49
|
+
delete process.env.NO_COLOR;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("a lexicon post-synth error fails the lint, at the project root and at src", async () => {
|
|
53
|
+
await project("MergeTre");
|
|
54
|
+
for (const path of [root, join(root, "src")]) {
|
|
55
|
+
const result = await lintCommand({ path, format: "stylish" });
|
|
56
|
+
expect(result.success).toBe(false);
|
|
57
|
+
const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH101");
|
|
58
|
+
expect(diag, result.output).toBeDefined();
|
|
59
|
+
expect(diag!.severity).toBe("error");
|
|
60
|
+
expect(diag!.message).toContain('"MergeTre"');
|
|
61
|
+
// No line of its own: reported at 1:1 in the file that declared the table.
|
|
62
|
+
expect(diag!.file).toBe(join(root, "src", "schema.ts"));
|
|
63
|
+
expect([diag!.line, diag!.column]).toEqual([1, 1]);
|
|
64
|
+
expect(result.output).toContain("SQLCH101");
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("a column type the pinned server does not have is reported (SQLCH121)", async () => {
|
|
69
|
+
await project("MergeTree", undefined, "UInt46");
|
|
70
|
+
const result = await lintCommand({ path: root, format: "stylish" });
|
|
71
|
+
expect(result.success).toBe(false);
|
|
72
|
+
const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH121");
|
|
73
|
+
expect(diag, result.output).toBeDefined();
|
|
74
|
+
expect(diag!.message).toContain("UInt46");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("postSynth: false lints source alone", async () => {
|
|
78
|
+
await project("MergeTre");
|
|
79
|
+
const result = await lintCommand({ path: root, format: "stylish", postSynth: false });
|
|
80
|
+
expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("a clean project reports nothing from the post-synth pass", async () => {
|
|
84
|
+
await project("MergeTree");
|
|
85
|
+
const result = await lintCommand({ path: root, format: "stylish" });
|
|
86
|
+
expect(result.diagnostics.filter((d) => /^SQL|^LEX/.test(d.ruleId)), result.output).toEqual([]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("lint.rules overrides a post-synth finding's severity, and turns it off", async () => {
|
|
90
|
+
await project("MergeTre", { SQLCH101: "warning" });
|
|
91
|
+
const warned = await lintCommand({ path: root, format: "stylish" });
|
|
92
|
+
expect(warned.diagnostics.find((d) => d.ruleId === "SQLCH101")?.severity).toBe("warning");
|
|
93
|
+
expect(warned.success).toBe(true);
|
|
94
|
+
|
|
95
|
+
await project("MergeTre", { SQLCH101: "off" });
|
|
96
|
+
const off = await lintCommand({ path: root, format: "stylish" });
|
|
97
|
+
expect(off.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("a target that does not build reports the build error and skips the checks", async () => {
|
|
101
|
+
await project("MergeTre");
|
|
102
|
+
// A table interpolating a name that is not declared does not build.
|
|
103
|
+
await writeFile(
|
|
104
|
+
join(root, "src", "broken.ts"),
|
|
105
|
+
'import { table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
|
|
106
|
+
'import { events } from "./schema";\n' +
|
|
107
|
+
"export const copy = table`CREATE TABLE shop.copy (id UInt64) ENGINE = MergeTree ORDER BY ${(events as any).columns.nope}`;\n",
|
|
108
|
+
);
|
|
109
|
+
const result = await lintCommand({ path: root, format: "stylish" });
|
|
110
|
+
expect(result.success).toBe(false);
|
|
111
|
+
const failures = result.diagnostics.filter((d) => d.ruleId === BUILD_FAILURE_RULE_ID);
|
|
112
|
+
expect(failures.length, result.output).toBeGreaterThan(0);
|
|
113
|
+
expect(failures.every((d) => d.severity === "error")).toBe(true);
|
|
114
|
+
expect(failures.map((d) => d.message).join("\n")).toContain("is undefined");
|
|
115
|
+
expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
-
import { lintCommand, isLintRule, loadPluginRules, LEXICON_RESOLUTION_RULE_ID,
|
|
2
|
+
import { lintCommand, isLintRule, loadPluginRules, LEXICON_RESOLUTION_RULE_ID, type LintOptions } from "./lint";
|
|
3
3
|
import { loadPlugins, resolveProjectLexicons } from "../plugins";
|
|
4
4
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { execFileSync } from "node:child_process";
|
|
8
|
-
import { mkdtempSync, realpathSync, symlinkSync } from "node:fs";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
8
|
import { params, setBuildParams } from "../../params";
|
|
11
9
|
|
|
12
10
|
describe("lintCommand", () => {
|
|
@@ -887,7 +885,7 @@ describe("lintCommand — a declared lexicon that cannot be resolved (#2222)", (
|
|
|
887
885
|
* `lintCommand` has no flags to read and passed nothing, so `params` stayed
|
|
888
886
|
* empty and OPS012 reported the activity contract violated for source that
|
|
889
887
|
* lints clean from a shell. That is how the root-examples gate
|
|
890
|
-
* (examples/root-examples-gate.test.ts) went red on github-pr-preview while
|
|
888
|
+
* (examples/root-examples-gate.e2e.test.ts) went red on github-pr-preview while
|
|
891
889
|
* `chant lint .` in the same directory exited 0, and it applied equally to
|
|
892
890
|
* `handleLint` over MCP and to test-utils' example harness.
|
|
893
891
|
*
|
|
@@ -962,108 +960,5 @@ describe("lintCommand build-time parameters (#2249)", () => {
|
|
|
962
960
|
});
|
|
963
961
|
});
|
|
964
962
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
* over an in-memory build of the lint target, the ones `chant build` runs.
|
|
968
|
-
* The sql lexicon's SQLCH101 is the issue's repro: `ENGINE = MergeTre` failed
|
|
969
|
-
* the build and linted clean. The project imports the workspace's sql
|
|
970
|
-
* lexicon through a `node_modules` link, as an installed project would.
|
|
971
|
-
*/
|
|
972
|
-
describe("lintCommand — lexicon post-synth checks (#3750)", () => {
|
|
973
|
-
const repoNodeModules = resolve(fileURLToPath(new URL(".", import.meta.url)), "../../../../../node_modules");
|
|
974
|
-
let root: string;
|
|
975
|
-
|
|
976
|
-
const schema = (engine: string, idType = "UInt64") =>
|
|
977
|
-
'import { database, table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
|
|
978
|
-
"export const shopDb = database`CREATE DATABASE shop ENGINE = Atomic`;\n" +
|
|
979
|
-
"export const events = table`\n" +
|
|
980
|
-
` CREATE TABLE \${shopDb}.events (id ${idType}, kind String)\n` +
|
|
981
|
-
` ENGINE = ${engine}\n` +
|
|
982
|
-
" ORDER BY (kind, id)`;\n";
|
|
983
|
-
|
|
984
|
-
async function project(engine: string, rules?: Record<string, string>, idType?: string): Promise<void> {
|
|
985
|
-
await writeFile(
|
|
986
|
-
join(root, "chant.config.json"),
|
|
987
|
-
JSON.stringify({ lexicons: ["sql"], sql: { dialect: "clickhouse" }, ...(rules ? { lint: { rules } } : {}) }),
|
|
988
|
-
);
|
|
989
|
-
await writeFile(join(root, "src", "schema.ts"), schema(engine, idType));
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
beforeEach(async () => {
|
|
993
|
-
root = realpathSync(mkdtempSync(join(tmpdir(), "chant-3750-")));
|
|
994
|
-
await mkdir(join(root, "src"), { recursive: true });
|
|
995
|
-
symlinkSync(repoNodeModules, join(root, "node_modules"), "dir");
|
|
996
|
-
process.env.NO_COLOR = "1";
|
|
997
|
-
});
|
|
998
|
-
|
|
999
|
-
afterEach(async () => {
|
|
1000
|
-
await rm(root, { recursive: true, force: true });
|
|
1001
|
-
delete process.env.NO_COLOR;
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
test("a lexicon post-synth error fails the lint, at the project root and at src", async () => {
|
|
1005
|
-
await project("MergeTre");
|
|
1006
|
-
for (const path of [root, join(root, "src")]) {
|
|
1007
|
-
const result = await lintCommand({ path, format: "stylish" });
|
|
1008
|
-
expect(result.success).toBe(false);
|
|
1009
|
-
const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH101");
|
|
1010
|
-
expect(diag, result.output).toBeDefined();
|
|
1011
|
-
expect(diag!.severity).toBe("error");
|
|
1012
|
-
expect(diag!.message).toContain('"MergeTre"');
|
|
1013
|
-
// No line of its own: reported at 1:1 in the file that declared the table.
|
|
1014
|
-
expect(diag!.file).toBe(join(root, "src", "schema.ts"));
|
|
1015
|
-
expect([diag!.line, diag!.column]).toEqual([1, 1]);
|
|
1016
|
-
expect(result.output).toContain("SQLCH101");
|
|
1017
|
-
}
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
test("a column type the pinned server does not have is reported (SQLCH121)", async () => {
|
|
1021
|
-
await project("MergeTree", undefined, "UInt46");
|
|
1022
|
-
const result = await lintCommand({ path: root, format: "stylish" });
|
|
1023
|
-
expect(result.success).toBe(false);
|
|
1024
|
-
const diag = result.diagnostics.find((d) => d.ruleId === "SQLCH121");
|
|
1025
|
-
expect(diag, result.output).toBeDefined();
|
|
1026
|
-
expect(diag!.message).toContain("UInt46");
|
|
1027
|
-
});
|
|
1028
|
-
|
|
1029
|
-
test("postSynth: false lints source alone", async () => {
|
|
1030
|
-
await project("MergeTre");
|
|
1031
|
-
const result = await lintCommand({ path: root, format: "stylish", postSynth: false });
|
|
1032
|
-
expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
test("a clean project reports nothing from the post-synth pass", async () => {
|
|
1036
|
-
await project("MergeTree");
|
|
1037
|
-
const result = await lintCommand({ path: root, format: "stylish" });
|
|
1038
|
-
expect(result.diagnostics.filter((d) => /^SQL|^LEX/.test(d.ruleId)), result.output).toEqual([]);
|
|
1039
|
-
});
|
|
1040
|
-
|
|
1041
|
-
test("lint.rules overrides a post-synth finding's severity, and turns it off", async () => {
|
|
1042
|
-
await project("MergeTre", { SQLCH101: "warning" });
|
|
1043
|
-
const warned = await lintCommand({ path: root, format: "stylish" });
|
|
1044
|
-
expect(warned.diagnostics.find((d) => d.ruleId === "SQLCH101")?.severity).toBe("warning");
|
|
1045
|
-
expect(warned.success).toBe(true);
|
|
1046
|
-
|
|
1047
|
-
await project("MergeTre", { SQLCH101: "off" });
|
|
1048
|
-
const off = await lintCommand({ path: root, format: "stylish" });
|
|
1049
|
-
expect(off.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
1050
|
-
});
|
|
1051
|
-
|
|
1052
|
-
test("a target that does not build reports the build error and skips the checks", async () => {
|
|
1053
|
-
await project("MergeTre");
|
|
1054
|
-
// A table interpolating a name that is not declared does not build.
|
|
1055
|
-
await writeFile(
|
|
1056
|
-
join(root, "src", "broken.ts"),
|
|
1057
|
-
'import { table } from "@intentius/chant-lexicon-sql/clickhouse";\n' +
|
|
1058
|
-
'import { events } from "./schema";\n' +
|
|
1059
|
-
"export const copy = table`CREATE TABLE shop.copy (id UInt64) ENGINE = MergeTree ORDER BY ${(events as any).columns.nope}`;\n",
|
|
1060
|
-
);
|
|
1061
|
-
const result = await lintCommand({ path: root, format: "stylish" });
|
|
1062
|
-
expect(result.success).toBe(false);
|
|
1063
|
-
const failures = result.diagnostics.filter((d) => d.ruleId === BUILD_FAILURE_RULE_ID);
|
|
1064
|
-
expect(failures.length, result.output).toBeGreaterThan(0);
|
|
1065
|
-
expect(failures.every((d) => d.severity === "error")).toBe(true);
|
|
1066
|
-
expect(failures.map((d) => d.message).join("\n")).toContain("is undefined");
|
|
1067
|
-
expect(result.diagnostics.some((d) => d.ruleId === "SQLCH101")).toBe(false);
|
|
1068
|
-
});
|
|
1069
|
-
});
|
|
963
|
+
// The lexicon post-synth pass over a project that imports the sql lexicon (#3750) builds
|
|
964
|
+
// that project and loads the lexicon; it is in lint-post-synth.e2e.test.ts (#3793).
|