Skip to content

Commit dd41f17

Browse files
PeliCopilot
authored andcommitted
Require crypto-generated delimiters for agent heredocs
Use fresh quoted RIG_ delimiters, check for complete-line collisions, and preserve literal closing tokens in guidance and launcher help. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent df28cf3 commit dd41f17

9 files changed

Lines changed: 63 additions & 17 deletions

File tree

‎.github/workflows/rig-skill-integration.lock.yml‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎.github/workflows/rig-skill-integration.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ post-steps:
5151

5252
Read the installed Rig skill and its running/engines reference. Run the following
5353
`rig` fence **once**, unchanged, using the installed skill's launcher in inline
54-
mode via `node <installed-skill-dir>/run.ts <<'RIG'`, with the fence contents
55-
followed by `RIG`. Redirect stdout to `/tmp/gh-aw/agent/rig-skill-integration.json`.
54+
mode. First generate a fresh delimiter: `RIG_` followed by
55+
`randomBytes(16).toString("hex")` from Node's `node:crypto`. Verify it is not a
56+
complete line of the fence contents; regenerate on collision. Use
57+
`node <installed-skill-dir>/run.ts <<'RIG_<generated-hex>'`, substituting the
58+
generated literal in both the single-quoted opener and the unquoted,
59+
unindented closing line. Never use a fixed delimiter or a shell variable.
60+
Redirect stdout to `/tmp/gh-aw/agent/rig-skill-integration.json`.
5661
Use the provided `COPILOT_SDK_URI`; do not start a second server or use `--server`.
5762
Use the SDK dependencies already installed in the agent container. The entry
5863
point does not install packages; do not run npm, npx, cat, mkdir, or other

‎README.md‎

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,19 @@ Its [integration guide](skills/rig/references/runtime.md#choosing-an-integration
9797
compares engine capabilities, model selection, tool ownership, and output
9898
enforcement.
9999

100+
For every heredoc below, replace `RIG_<generated-hex>` with a fresh `RIG_`
101+
delimiter generated using `node:crypto`'s `randomBytes(16).toString("hex")`.
102+
Check it is not an entire line of the contents, single-quote the opener, and
103+
repeat the exact unquoted delimiter alone on the closing line. See the
104+
[inline-program guide](skills/rig/references/runtime.md#inline-programs) for the
105+
generation command; do not reuse fixed delimiters or shell variables.
106+
100107
**Design on the fly** — just describe what you want as a string and let the model figure out the rest:
101108

102109
```bash
103-
node skills/rig/run.ts <<'RIG'
110+
node skills/rig/run.ts <<'RIG_<generated-hex>'
104111
export default "Run npm test, diagnose any failures, apply the smallest safe fix, and repeat up to 3 times.";
105-
RIG
112+
RIG_<generated-hex>
106113
```
107114
108115
Or ask Copilot (with the skill) to generate a full program for you. Describe your goal in natural language and Copilot returns a runnable `rig` markdown fence like this:
@@ -137,17 +144,17 @@ export default ralfLoop;
137144
Pass the fence contents directly to the launcher with a heredoc:
138145
139146
```bash
140-
node skills/rig/run.ts <<'RIG'
147+
node skills/rig/run.ts <<'RIG_<generated-hex>'
141148
// Paste the rig fence contents here.
142-
RIG
149+
RIG_<generated-hex>
143150
```
144151
145152
Or run a program file:
146153
147154
```bash
148-
node skills/rig/run.ts src/program.ts <<'INPUT'
155+
node skills/rig/run.ts src/program.ts <<'RIG_<generated-hex>'
149156
Review this diff
150-
INPUT
157+
RIG_<generated-hex>
151158
```
152159
153160
Use `--typecheck` to validate a program without running it:

‎skills/rig/SKILL.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,12 @@ node skills/rig/run.ts --typecheck < program.ts
9494

9595
For an installed skill, replace `skills/rig` with its installed directory. Use
9696
`run.ts` to launch without installing packages; inline programs use
97-
`node <skill-dir>/run.ts <<'RIG'` with the program followed by `RIG`.
97+
`node <skill-dir>/run.ts <<'RIG_<generated-hex>'`. For each heredoc, generate a
98+
fresh `RIG_` delimiter with `node:crypto`'s `randomBytes(16).toString("hex")`.
99+
Ensure it is not a complete line in the contents; regenerate on collision.
100+
Single-quote the opening delimiter and repeat the same literal, unquoted
101+
delimiter alone on the closing line. Never use a fixed delimiter or shell
102+
variable; see [Running and engines](references/runtime.md).
98103
Install the skill with `gh skill install githubnext/rig rig`.
99104
Assume SDKs are already installed in the agent container; do not install them.
100105
Only `node` needs a Bash tool grant for launching an installed skill; grant

‎skills/rig/references/runtime.md‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,25 @@ Read this reference when launching or typechecking programs, handling stdin, or
66

77
Treat a fenced `rig` block as a runnable program. Pass its contents to the launcher with a heredoc:
88

9+
Before constructing each heredoc command, generate a fresh delimiter using
10+
Node's cryptographic random source (no additional Bash tool grant):
11+
12+
```bash
13+
node --input-type=module -e 'import { randomBytes } from "node:crypto"; console.log("RIG_" + randomBytes(16).toString("hex"));'
14+
```
15+
16+
Check that the generated delimiter is not an entire line of the contents,
17+
including a possible trailing `\r`; regenerate if it collides. Substitute the
18+
result for `RIG_<generated-hex>` below. Single-quote the opener to suppress shell
19+
expansion, and put the same literal delimiter, unquoted and unindented, alone on
20+
the closing line. Do not reuse a fixed delimiter or use a shell variable as the
21+
delimiter: Bash does not expand delimiter words.
22+
923
```bash
10-
node skills/rig/run.ts <<'RIG'
24+
node skills/rig/run.ts <<'RIG_<generated-hex>'
1125
// Agent role: summarize this repository in one sentence.
1226
export default "Summarize this repository in one sentence.";
13-
RIG
27+
RIG_<generated-hex>
1428
```
1529
1630
Inline mode:
@@ -54,9 +68,9 @@ required by the program's own tool calls separately.
5468
Export the root and pass stdin plus the file path:
5569
5670
```bash
57-
node skills/rig/run.ts src/program.ts <<'INPUT'
71+
node skills/rig/run.ts src/program.ts <<'RIG_<generated-hex>'
5872
Review this diff
59-
INPUT
73+
RIG_<generated-hex>
6074
```
6175
6276
Stdin coercion follows the root schema:

‎skills/rig/rig.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,9 +1946,12 @@ function renderLauncherUsage(scriptName: string): string {
19461946
"Examples:",
19471947
` node ${scriptName} < ./program.ts`,
19481948
` node ${scriptName} --typecheck < ./program.ts`,
1949-
` node ${scriptName} src/program.ts <<'INPUT'`,
1949+
` node ${scriptName} src/program.ts <<'RIG_<generated-hex>'`,
19501950
" Summarize this repository",
1951-
" INPUT",
1951+
"RIG_<generated-hex>",
1952+
"",
1953+
"Replace RIG_<generated-hex> with a fresh RIG_ + node:crypto randomBytes(16).toString(\"hex\").",
1954+
"Ensure it is not a complete input line; quote the opener and close with the same literal alone.",
19521955
].join("\n");
19531956
}
19541957

‎src/launcher.test.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ it("prints launcher help for common help invocations", async () => {
240240
expect(output).toContain("--typecheck < ./program.ts");
241241
expect(output).not.toContain("cat ");
242242
expect(output).not.toContain("echo ");
243+
expect(output).toContain('randomBytes(16).toString("hex")');
244+
expect(output).toContain("<<'RIG_<generated-hex>'");
245+
expect(output).toContain("\nRIG_<generated-hex>\n");
243246
}
244247
expect(mocks.createSession).not.toHaveBeenCalled();
245248
});

‎src/rig-skill-workflow.test.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ afterEach(() => {
7272
describe("Rig skill agentic workflow", () => {
7373
it("requires only node for installed-skill bootstrap and launch", () => {
7474
expect(markdown).toContain('bash: ["node"]');
75-
expect(markdown).toContain("node <installed-skill-dir>/run.ts <<'RIG'");
75+
expect(markdown).toContain("node <installed-skill-dir>/run.ts <<'RIG_<generated-hex>'");
76+
expect(markdown).toContain('randomBytes(16).toString("hex")');
77+
expect(markdown).toContain("regenerate on collision");
7678
});
7779

7880
it("runs the actual workflow fence with exactly three small SDK calls", async () => {

‎src/skill.test.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ it("keeps every canonical skill reference available", () => {
2525
}
2626
});
2727

28+
it("requires fresh crypto-generated and quoted heredoc delimiters", () => {
29+
expect(canonicalManifest).toContain('randomBytes(16).toString("hex")');
30+
expect(canonicalManifest).toContain("regenerate on collision");
31+
expect(canonicalManifest).toContain("Single-quote the opening delimiter");
32+
expect(canonicalManifest).not.toContain("<<'RIG'");
33+
});
34+
2835
it("exposes the same public modules from the standalone skill and repository", () => {
2936
const repositoryPackage = JSON.parse(readFileSync(resolve(repoRoot, "package.json"), "utf8"));
3037
const skillPackage = JSON.parse(readFileSync(resolve(skillRoot, "package.json"), "utf8"));

0 commit comments

Comments
 (0)