Skip to content

Deliver SDK spec and replay manifests through Tailscale exits - #264

Closed
peakematt wants to merge 3 commits into
mainfrom
codex/spec-changes-tailscale
Closed

peakematt wants to merge 3 commits into
mainfrom
codex/spec-changes-tailscale

Conversation

@peakematt

@peakematt peakematt commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Both normal spec-change delivery and confirmed historical replay currently reach the SDK bot over the public runner network. This moves their signed POSTs onto ephemeral Tailscale runners through an explicitly selected internal exit, using the existing NAT WAF allowance.

Both data-building jobs have no OIDC or signing secret. Separate dependency-free delivery jobs use distinct exact workflow/event identities, validate their workflow/ref/event and selected exit, verify the same-host NAT source, and sign the exact artifact bytes. Replay keeps dry-run, default-branch checking and explicit push confirmation, preflights all targets, and sends changed manifests sequentially in input order. Its script has no remaining direct fetch implementation; legacy --push delegates to the same guarded transport.

All requests and retries use explicit IPv4 SOCKS5 with curlrc, NO_PROXY bypass and redirects disabled. Before HTTP, delivery pins the destination IPv4 and installs a disposable-runner OUTPUT reject for direct TCP/443 to that IP, including tailscaled's host-network fallback if its route disappears. Failure to install the guard stops delivery.

This is controlled exit egress to the existing public Cloudflare Worker, not a tailnet-only Worker endpoint. The dedicated policy grants general IPv4 Internet HTTPS via internal exits; the script fixes the target host/path. No bot deployment is needed.

Depends on infra #2157. Complete administrator bootstrap, the reviewed human apply, and seven public Actions variables before merging this one. After bootstrap the infra plan must not mutate an existing identity. Keep SPEC_CHANGES_SECRET unchanged. Verify both producer events and a reviewed, explicitly requested replay push, bot manifest rows and ephemeral cleanup. Rollout details.

The Socket warning review traces version to the vendor download and statedir to argument-array spawn. Our inputs are a fixed version and omitted memory-only state; neither warning traces an OIDC secret. The executed bundle masks the JWT before returning it, although it is briefly present in CLI argv on the isolated runner. The signing secret is scoped only to the later delivery step. No warnings were suppressed.

Validation: all 18 caller/replay tests passed under Node 24.22.1, including exact-byte signing, ordered replay/preflight/confirmation checks and real curl failure with a closed loopback proxy. Actionlint passed for all three changed workflows; diff whitespace checks passed. These are local/static checks. Live OIDC, policy enforcement, NAT/Worker access, Linux firewall enforcement and cleanup remain rollout checks. No production replay was run.

@socket-security

socket-security Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Priority Alert  (click "▶" to expand/collapse) Action
Medium priority
Input argument leak: github tailscale/github-action exposes an input argument into sink

Location: Package overview

From: .github/workflows/replay-spec-changes.yml → github/tailscale/github-action@064b10558093f38325e838ddea35486bdc6b1d5c

ℹ Read more on: This package | This alert | What are GitHub Actions taint flows?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Validate and sanitize all input arguments before using them in dangerous operations. Use parameterized commands or APIs instead of string concatenation for shell commands.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore github/tailscale/github-action@064b10558093f38325e838ddea35486bdc6b1d5c. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn
Medium priority
Input argument leak: github tailscale/github-action exposes an input argument into sink

Location: Package overview

From: .github/workflows/replay-spec-changes.yml → github/tailscale/github-action@064b10558093f38325e838ddea35486bdc6b1d5c

ℹ Read more on: This package | This alert | What are GitHub Actions taint flows?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Validate and sanitize all input arguments before using them in dangerous operations. Use parameterized commands or APIs instead of string concatenation for shell commands.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore github/tailscale/github-action@064b10558093f38325e838ddea35486bdc6b1d5c. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn

View full report

@peakematt peakematt changed the title Deliver spec manifests through verified Tailscale exits Deliver SDK spec and replay manifests through Tailscale exits Nov 5, 2026
@peakematt
peakematt marked this pull request as ready for review November 5, 2026 19:13

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@greptile-apps

greptile-apps Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The PR changes how two spec-manifest workflows reach the existing SDK bot.

The PR appears safe to merge, with a non-blocking fix recommended for an empty --prepare-delivery value.

Findings

  1. P2 Missing directory silently skips preparation ▶
Fix with agent prompt
### Issue 1
scripts/replay-spec-changes.mjs:111
`--prepare-delivery` accepts a missing or empty directory as `""`. With otherwise valid inputs, the script then treats the command as a dry run and exits successfully without writing delivery files. Reject an empty directory when this option is supplied, and add a test for that case.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

The PR moves normal and historical spec-change delivery into separate Tailscale jobs.

  • Spec-change manifests reach the SDK bot through a checked Tailscale exit.
  • Confirmed replay sends historical manifests through the shared delivery route.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Spec merge or manual replay] --> B[Build and check manifests]
  B --> C[Same-run data artifact]
  C --> D[Isolated delivery job]
  D --> E[Check workflow and Tailscale exit]
  E --> F[Pin IPv4 and block direct connection]
  F --> G[Check NAT through SOCKS5]
  G --> H[Sign bytes and POST through exit]
  H --> I[SDK bot]
Loading

Reviews (1) · Last reviewed commit: "Migrate confirmed historical replays to ..." · Reviewed by Greptile

else if (arg === "--repository") args.repository = argv[++i] ?? "";
else if (arg === "--bot-url") args.botUrl = argv[++i] ?? "";
else if (arg === "--push") args.push = true;
else if (arg === "--prepare-delivery") args.prepareDelivery = argv[++i] ?? "";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing directory silently skips preparation

--prepare-delivery accepts a missing or empty directory as "". With otherwise valid inputs, the script then treats the command as a dry run and exits successfully without writing delivery files. Reject an empty directory when this option is supplied, and add a test for that case.

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/replay-spec-changes.mjs
Line: 111

Comment:
**Missing directory silently skips preparation**

`--prepare-delivery` accepts a missing or empty directory as `""`. With otherwise valid inputs, the script then treats the command as a dry run and exits successfully without writing delivery files. Reject an empty directory when this option is supplied, and add a test for that case.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@gjtorikian

Copy link
Copy Markdown
Collaborator

going to pull for this info rather than have GHA POST to the bot

@gjtorikian gjtorikian closed this Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants