@intentius/plywood 0.3.2 → 0.3.7
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/image-digests.json +4 -0
- package/dist/plywood.mjs +465 -1059
- package/dist/plywood.mjs.map +4 -4
- package/package.json +6 -6
- package/plywood.schema.json +3 -3
- package/templates/agent-guard/bin/plunge +0 -27
- package/templates/agent-guard/bin/pulumi +0 -27
- package/templates/agent-guard/plywood-guard.mjs +0 -60
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/plywood",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Pulumi ops and governance.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"prepack": "node scripts/build-cli.mjs"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@intentius/chant": "0.124.
|
|
38
|
-
"@intentius/chant-lexicon-forgejo": "0.124.
|
|
39
|
-
"@intentius/chant-lexicon-github": "0.124.
|
|
40
|
-
"@intentius/chant-lexicon-gitlab": "0.124.
|
|
41
|
-
"@intentius/chant-lexicon-pulumi": "0.124.
|
|
37
|
+
"@intentius/chant": "0.124.84",
|
|
38
|
+
"@intentius/chant-lexicon-forgejo": "0.124.84",
|
|
39
|
+
"@intentius/chant-lexicon-github": "0.124.84",
|
|
40
|
+
"@intentius/chant-lexicon-gitlab": "0.124.84",
|
|
41
|
+
"@intentius/chant-lexicon-pulumi": "0.124.84"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/plywood.schema.json
CHANGED
|
@@ -219,8 +219,8 @@
|
|
|
219
219
|
},
|
|
220
220
|
"preview": {
|
|
221
221
|
"type": "boolean",
|
|
222
|
-
"default":
|
|
223
|
-
"description": "true: plywood init sets approvals.preview in the waves spec, so a merged wave applies only the plans its pull request previewed, or exits 4.
|
|
222
|
+
"default": true,
|
|
223
|
+
"description": "true (the default): plywood init sets approvals.preview in the waves spec, so a merged wave applies only the plans its pull request previewed, or exits 4. false leaves it out."
|
|
224
224
|
},
|
|
225
225
|
"approval_rules": {
|
|
226
226
|
"type": "object",
|
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
"repo",
|
|
287
287
|
"ref"
|
|
288
288
|
],
|
|
289
|
-
"description": "A shared rule set from a git ref, fetched by the job at the ref the base names
|
|
289
|
+
"description": "A shared rule set from a git ref, fetched by the job at the ref the base names. packs are then paths inside it.",
|
|
290
290
|
"properties": {
|
|
291
291
|
"repo": {
|
|
292
292
|
"type": "string",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
# plywood's agent guard wrapper for plunge (plywood#19), written by 'plywood guard install'.
|
|
3
|
-
# First on PATH in an agent session: with PLYWOOD_AGENT_GUARD=1 or CLAUDECODE=1
|
|
4
|
-
# it refuses 'plunge up', 'plunge update' and 'plunge destroy', and runs every other
|
|
5
|
-
# command with the real plunge further down PATH.
|
|
6
|
-
self_dir=$(cd "$(dirname "$0")" && pwd)
|
|
7
|
-
if [ "${PLYWOOD_AGENT_GUARD:-}" = "1" ] || [ "${CLAUDECODE:-}" = "1" ]; then
|
|
8
|
-
skip=0
|
|
9
|
-
for arg in "$@"; do
|
|
10
|
-
if [ "$skip" = 1 ]; then skip=0; continue; fi
|
|
11
|
-
case "$arg" in
|
|
12
|
-
-C|--cwd|-s|--stack|--color|--config-file|--logflow|-v|--verbose|--tracing|--profiling|--memprofilerate) skip=1 ;;
|
|
13
|
-
-*) ;;
|
|
14
|
-
up|update|destroy)
|
|
15
|
-
echo "plywood guard: an agent session does not run 'plunge $arg'. Open a pull request; plywood previews it, and the update runs after a person approves the digest." >&2
|
|
16
|
-
exit 1 ;;
|
|
17
|
-
*) break ;;
|
|
18
|
-
esac
|
|
19
|
-
done
|
|
20
|
-
fi
|
|
21
|
-
IFS=:
|
|
22
|
-
for dir in $PATH; do
|
|
23
|
-
[ "$(cd "$dir" 2>/dev/null && pwd)" = "$self_dir" ] && continue
|
|
24
|
-
if [ -x "$dir/plunge" ]; then exec "$dir/plunge" "$@"; fi
|
|
25
|
-
done
|
|
26
|
-
echo "plywood guard: no plunge on PATH after $self_dir" >&2
|
|
27
|
-
exit 127
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
# plywood's agent guard wrapper for pulumi (plywood#19), written by 'plywood guard install'.
|
|
3
|
-
# First on PATH in an agent session: with PLYWOOD_AGENT_GUARD=1 or CLAUDECODE=1
|
|
4
|
-
# it refuses 'pulumi up', 'pulumi update' and 'pulumi destroy', and runs every other
|
|
5
|
-
# command with the real pulumi further down PATH.
|
|
6
|
-
self_dir=$(cd "$(dirname "$0")" && pwd)
|
|
7
|
-
if [ "${PLYWOOD_AGENT_GUARD:-}" = "1" ] || [ "${CLAUDECODE:-}" = "1" ]; then
|
|
8
|
-
skip=0
|
|
9
|
-
for arg in "$@"; do
|
|
10
|
-
if [ "$skip" = 1 ]; then skip=0; continue; fi
|
|
11
|
-
case "$arg" in
|
|
12
|
-
-C|--cwd|-s|--stack|--color|--config-file|--logflow|-v|--verbose|--tracing|--profiling|--memprofilerate) skip=1 ;;
|
|
13
|
-
-*) ;;
|
|
14
|
-
up|update|destroy)
|
|
15
|
-
echo "plywood guard: an agent session does not run 'pulumi $arg'. Open a pull request; plywood previews it, and the update runs after a person approves the digest." >&2
|
|
16
|
-
exit 1 ;;
|
|
17
|
-
*) break ;;
|
|
18
|
-
esac
|
|
19
|
-
done
|
|
20
|
-
fi
|
|
21
|
-
IFS=:
|
|
22
|
-
for dir in $PATH; do
|
|
23
|
-
[ "$(cd "$dir" 2>/dev/null && pwd)" = "$self_dir" ] && continue
|
|
24
|
-
if [ -x "$dir/pulumi" ]; then exec "$dir/pulumi" "$@"; fi
|
|
25
|
-
done
|
|
26
|
-
echo "plywood guard: no pulumi on PATH after $self_dir" >&2
|
|
27
|
-
exit 127
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// plywood's agent guard, a Claude Code PreToolUse hook on Bash (plywood#19).
|
|
3
|
-
// Written by `plywood guard install`; `plywood guard install` writes it again.
|
|
4
|
-
// It blocks a command line that runs `pulumi up`, `pulumi destroy` or
|
|
5
|
-
// `plunge up` (and `update`, their alias): an agent opens a pull request,
|
|
6
|
-
// and the update runs after a person approves its digest. Exit 2 is Claude
|
|
7
|
-
// Code's code for a blocked call; its stderr goes back to the agent.
|
|
8
|
-
|
|
9
|
-
const GUARDED = { pulumi: ["up", "update", "destroy"], plunge: ["up", "update", "destroy"] };
|
|
10
|
-
const VALUED_GLOBALS = new Set(["-C", "--cwd", "-s", "--stack", "--color", "--config-file", "--logflow", "-v", "--verbose", "--tracing", "--profiling", "--memprofilerate"]);
|
|
11
|
-
const LAUNCHERS = new Set(["env", "npx", "sudo", "command", "exec", "nohup", "time", "xargs"]);
|
|
12
|
-
|
|
13
|
-
function segments(line) {
|
|
14
|
-
return line
|
|
15
|
-
.split(/\|\||&&|[;|\n`]|\$\(|\)/)
|
|
16
|
-
.map((seg) => (seg.match(/'[^']*'|"[^"]*"|\S+/g) ?? []).map((t) => t.replace(/^['"]|['"]$/g, "")))
|
|
17
|
-
.filter((t) => t.length > 0);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** The refused engine and subcommand, or undefined. Kept in step with src/guard.ts `guardVerdict`. */
|
|
21
|
-
export function verdict(line) {
|
|
22
|
-
for (const words of segments(line)) {
|
|
23
|
-
let i = 0;
|
|
24
|
-
while (i < words.length && (LAUNCHERS.has(words[i]) || /^[A-Za-z_][A-Za-z0-9_]*=/.test(words[i]) || (words[i - 1] === "env" && words[i].startsWith("-")))) i++;
|
|
25
|
-
const bin = (words[i] ?? "").split("/").pop();
|
|
26
|
-
const refused = GUARDED[bin];
|
|
27
|
-
if (!refused) continue;
|
|
28
|
-
for (let j = i + 1; j < words.length; j++) {
|
|
29
|
-
const w = words[j];
|
|
30
|
-
if (w.startsWith("-")) {
|
|
31
|
-
if (VALUED_GLOBALS.has(w)) j++;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (refused.includes(w)) return { engine: bin, subcommand: w };
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function main() {
|
|
42
|
-
let input = "";
|
|
43
|
-
for await (const chunk of process.stdin) input += chunk;
|
|
44
|
-
let call;
|
|
45
|
-
try {
|
|
46
|
-
call = JSON.parse(input);
|
|
47
|
-
} catch {
|
|
48
|
-
return 0;
|
|
49
|
-
}
|
|
50
|
-
const command = call?.tool_input?.command;
|
|
51
|
-
if (typeof command !== "string") return 0;
|
|
52
|
-
const v = verdict(command);
|
|
53
|
-
if (!v) return 0;
|
|
54
|
-
process.stderr.write(`plywood guard: an agent session does not run '${v.engine} ${v.subcommand}'. Open a pull request; plywood previews it, and the update runs after a person approves the digest.\n`);
|
|
55
|
-
return 2;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (process.argv[1] && import.meta.url.endsWith("/plywood-guard.mjs") && process.argv[1].endsWith("plywood-guard.mjs")) {
|
|
59
|
-
main().then((code) => process.exit(code));
|
|
60
|
-
}
|