tamperward 2.16.0 → 2.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/cli/index.js +76 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -325,8 +325,14 @@ Public rulesets can be read anonymously; set `GH_TOKEN` or `GITHUB_TOKEN` when
|
|
|
325
325
|
authentication is required.
|
|
326
326
|
|
|
327
327
|
A real deployment needs a verify command configured — the generated CI verify step
|
|
328
|
-
**fails closed (exit 2) without one** rather than passing quietly.
|
|
329
|
-
|
|
328
|
+
**fails closed (exit 2) without one** rather than passing quietly. Since 2.16.1,
|
|
329
|
+
`tamperward init` ends with a separate **VERIFICATION SETUP** status: it says either
|
|
330
|
+
`verification configured — <command>` or prominently reports
|
|
331
|
+
`INCOMPLETE: verification not configured — CI will fail closed`. It can suggest a
|
|
332
|
+
single high-confidence command such as `npm test`, `pytest`, `tox`, `cargo test`
|
|
333
|
+
or `go test ./...`; multiple candidates are listed without choosing one. Suggestions
|
|
334
|
+
are advisory only — init never writes an inferred verifier command because that command
|
|
335
|
+
is part of the trust anchor. In `.tamperward.yml`:
|
|
330
336
|
|
|
331
337
|
```yaml
|
|
332
338
|
verify:
|
package/dist/cli/index.js
CHANGED
|
@@ -8173,6 +8173,78 @@ function hooksShapeError(hooks) {
|
|
|
8173
8173
|
}
|
|
8174
8174
|
return null;
|
|
8175
8175
|
}
|
|
8176
|
+
function verifierCandidates(cwd) {
|
|
8177
|
+
const candidates = [];
|
|
8178
|
+
const add = (command) => {
|
|
8179
|
+
if (!candidates.includes(command)) candidates.push(command);
|
|
8180
|
+
};
|
|
8181
|
+
try {
|
|
8182
|
+
const pkg = JSON.parse(readFileSync11(join12(cwd, "package.json"), "utf8"));
|
|
8183
|
+
const test = pkg.scripts?.test;
|
|
8184
|
+
if (typeof test === "string" && test.trim() !== "" && !/error:\s*no test specified/i.test(test)) add("npm test");
|
|
8185
|
+
} catch {
|
|
8186
|
+
}
|
|
8187
|
+
try {
|
|
8188
|
+
const pyproject = readFileSync11(join12(cwd, "pyproject.toml"), "utf8");
|
|
8189
|
+
if (/^\s*\[tool\.pytest(?:\.ini_options)?\]\s*$/m.test(pyproject)) add("pytest");
|
|
8190
|
+
} catch {
|
|
8191
|
+
}
|
|
8192
|
+
if (existsSync9(join12(cwd, "pytest.ini"))) add("pytest");
|
|
8193
|
+
try {
|
|
8194
|
+
const setupCfg = readFileSync11(join12(cwd, "setup.cfg"), "utf8");
|
|
8195
|
+
if (/^\s*\[tool:pytest\]\s*$/m.test(setupCfg)) add("pytest");
|
|
8196
|
+
} catch {
|
|
8197
|
+
}
|
|
8198
|
+
try {
|
|
8199
|
+
const tox = readFileSync11(join12(cwd, "tox.ini"), "utf8");
|
|
8200
|
+
if (/^\s*\[tox\]\s*$/m.test(tox)) add("tox");
|
|
8201
|
+
} catch {
|
|
8202
|
+
}
|
|
8203
|
+
try {
|
|
8204
|
+
const cargo = readFileSync11(join12(cwd, "Cargo.toml"), "utf8");
|
|
8205
|
+
if (/^\s*\[(?:package|workspace)\]\s*(?:#.*)?$/m.test(cargo)) add("cargo test");
|
|
8206
|
+
} catch {
|
|
8207
|
+
}
|
|
8208
|
+
try {
|
|
8209
|
+
const goMod = readFileSync11(join12(cwd, "go.mod"), "utf8");
|
|
8210
|
+
if (/^\s*module\s+\S+\s*(?:\/\/.*)?$/m.test(goMod)) add("go test ./...");
|
|
8211
|
+
} catch {
|
|
8212
|
+
}
|
|
8213
|
+
return candidates;
|
|
8214
|
+
}
|
|
8215
|
+
function verifierSetupMessage(cwd) {
|
|
8216
|
+
try {
|
|
8217
|
+
const policy = loadPolicy(cwd);
|
|
8218
|
+
const command = policy.verify?.command?.trim();
|
|
8219
|
+
if (command) return `verification configured \u2014 ${command}`;
|
|
8220
|
+
} catch (e) {
|
|
8221
|
+
return `INCOMPLETE: verification not configured \u2014 policy cannot currently be loaded; CI will fail closed until the policy is fixed (${errText3(e)}).`;
|
|
8222
|
+
}
|
|
8223
|
+
const candidates = verifierCandidates(cwd);
|
|
8224
|
+
const lines = [
|
|
8225
|
+
"INCOMPLETE: verification not configured \u2014 CI will fail closed until .tamperward.yml names a trusted suite command."
|
|
8226
|
+
];
|
|
8227
|
+
if (candidates.length === 1) {
|
|
8228
|
+
lines.push(`Suggested verifier command: ${candidates[0]}`);
|
|
8229
|
+
lines.push("Review it, then add:");
|
|
8230
|
+
lines.push("verify:");
|
|
8231
|
+
lines.push(` command: "${candidates[0]}"`);
|
|
8232
|
+
lines.push(" budget: 300");
|
|
8233
|
+
} else if (candidates.length > 1) {
|
|
8234
|
+
lines.push(`Detected verifier candidates: ${candidates.join(", ")}`);
|
|
8235
|
+
lines.push("Choose the suite that defines merge authority, then add for example:");
|
|
8236
|
+
lines.push("verify:");
|
|
8237
|
+
lines.push(' command: "<reviewed suite command>"');
|
|
8238
|
+
lines.push(" budget: 300");
|
|
8239
|
+
} else {
|
|
8240
|
+
lines.push("Add the reviewed suite command to .tamperward.yml, for example:");
|
|
8241
|
+
lines.push("verify:");
|
|
8242
|
+
lines.push(' command: "<your test command>"');
|
|
8243
|
+
lines.push(" budget: 300");
|
|
8244
|
+
}
|
|
8245
|
+
lines.push("TamperWard does not write an inferred verifier command automatically because it is part of the trust anchor.");
|
|
8246
|
+
return lines.join("\n");
|
|
8247
|
+
}
|
|
8176
8248
|
function planPolicy(cwd) {
|
|
8177
8249
|
const path = join12(cwd, POLICY_FILE);
|
|
8178
8250
|
if (existsSync9(path)) {
|
|
@@ -8563,6 +8635,10 @@ WARNING (${a.item}): ${a.warning}
|
|
|
8563
8635
|
}
|
|
8564
8636
|
const errors = plan.filter((a) => a.status === "error");
|
|
8565
8637
|
const changed = opts.dryRun ? plan.filter((a) => a.apply).length : applied;
|
|
8638
|
+
w.write(`
|
|
8639
|
+
VERIFICATION SETUP
|
|
8640
|
+
${verifierSetupMessage(cwd)}
|
|
8641
|
+
`);
|
|
8566
8642
|
if (errors.length) {
|
|
8567
8643
|
w.write(`
|
|
8568
8644
|
tamperward init: ${errors.length} item(s) need your attention above; the rest ${opts.dryRun ? "are planned" : "were applied"}.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tamperward",
|
|
3
|
-
"version": "2.16.
|
|
3
|
+
"version": "2.16.1",
|
|
4
4
|
"description": "The deterministic agent-integrity gate. One ruleset, evaluated on the actual diff/commands as a verdict, enforced everywhere a change can be made.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "hexrift",
|