All posts
Strategy6 min read

Sigstore-Signed Git Attestations for Internal Scripts in Scheduled Jobs and Webhooks

Jamie

Sigstore-Signed Git Attestations for Internal Scripts in Scheduled Jobs and Webhooks

Why internal scripts need a supply-chain pattern

Scheduled jobs and webhook endpoints often sit in an uncomfortable middle ground: they’re “internal,” so they bypass the rigor applied to customer-facing services, but they still handle production data, credentials, and side effects like billing changes, user provisioning, or marketing spend. The most common failure mode isn’t a sophisticated attacker—it’s an accidental change that gets deployed outside of review, a copied script that drifts from Git, or a webhook endpoint running a different revision than the one incident response is auditing.

A practical pattern to reduce that risk is to treat scripts like release artifacts: signed, attestable, and verifiable at execution time. Sigstore brings modern signing and transparency to this workflow, while Git attestations let you prove a script came from a specific repository state. Together, they create a simple rule for scheduled jobs and webhooks: if it isn’t signed and Git-attested, it doesn’t run.

The pattern in one sentence

Build the runnable script artifact from a Git commit, generate a Sigstore-backed attestation tying the artifact digest to that commit, and enforce verification in the scheduler/webhook runtime before execution.

Threat model for cron and webhooks

You don’t need a full enterprise threat model to get value here. The pattern protects against a few recurring classes of issues:

  • Out-of-band edits (hotfixing a server file, editing a container live, “just this once” changes).
  • Credential misuse (a compromised CI token or developer workstation pushing unreviewed code).
  • Artifact substitution (the job runs “something,” but you can’t prove it’s the reviewed revision).
  • Rollback ambiguity (you can roll back code, but can’t prove which artifact ran during the incident window).
  • Supply chain drift (dependencies or build steps differ between what was reviewed and what executes).

What Sigstore and Git attestations give you

Sigstore (notably cosign) makes signing more usable by supporting ephemeral keys and identity-based signing, and by anchoring trust via public transparency logs. Practically, you can sign artifacts without distributing long-lived private keys in the old PGP sense.

Git attestations (or provenance-style statements linked to a commit) let you prove that the artifact digest corresponds to a specific Git tree/revision. This matters when the runtime is not executing from the repository directly (common for jobs and webhooks that run packaged bundles, containers, or prebuilt script tarballs).

Combined, you get two critical properties:

  • Authenticity: “This was produced by our CI identity and signed.”
  • Traceability: “This maps to commit X in repo Y, with a verifiable digest.”

End-to-end flow for signed, attested scripts

1) Define the runnable artifact

Pick a stable “thing” you can hash:

  • A container image for the job runner
  • A zip/tar bundle containing the script plus lockfiles
  • A compiled binary (Go) or packaged node/python environment

The key is that your scheduler/webhook runtime should execute that artifact, not a mutable working directory. Mutable directories are where drift lives.

2) Build in CI from a Git commit

Make CI the only place that produces production artifacts. Enforce branch protections, require review, and keep the build steps deterministic enough that the artifact digest is stable across rebuilds (or at least reproducible within controlled CI).

3) Generate a Sigstore signature and a Git attestation

During CI, sign the artifact digest and produce an attestation that binds:

  • repository identifier
  • commit SHA
  • artifact digest (e.g., OCI image digest or SHA256 of a bundle)
  • builder identity (CI workflow identity)

Store the signature/attestation alongside the artifact (for OCI images, this is typically in the registry as related objects). The operational goal is simple: the runtime can fetch the artifact and the proof needed to verify it.

4) Enforce verification at execution time

This is where the pattern actually becomes a security control instead of documentation. Before running a scheduled job or handling a webhook, the execution environment should:

  • resolve the artifact by immutable digest
  • verify the Sigstore signature
  • verify the Git attestation matches the expected repo + commit policy
  • fail closed if verification fails

Failing closed is non-negotiable. A “warn and run” mode is useful during rollout, but it cannot be the steady state for high-impact jobs.

5) Make policy explicit

Write down the policy the verifier enforces. Examples:

  • Only artifacts built by github-actions workflow release.yml are allowed.
  • Only commits on main with a required review count are allowed (enforced via branch protections, then trusted via CI identity).
  • Only artifacts from repository org/internal-automation are allowed for finance-impacting jobs.

This is also where teams often discover that their “internal” jobs are cross-cutting systems that deserve clearer ownership and review boundaries—similar to how integration debt accumulates when automations proliferate without structure (see the idea of an integration debt audit applied to job runners and webhook endpoints).

Applying the pattern to scheduled jobs

For cron-like workloads, the biggest win is eliminating “mystery revisions.” A good operational setup looks like this:

  • Schedule points to an artifact digest, not a tag like latest.
  • Runtime verifies signature + attestation before every run (or before pulling a new digest).
  • Logs record the digest and commit SHA so incident response can answer “what ran at 03:12 UTC?” without guesswork.

If your org already relies on internal scripting for ETL, billing sync, or postbacks, this also helps reduce false alarms caused by drift and inconsistent behavior over time. It pairs well with measurement hygiene practices such as modeling reporting delays, because you can separate “data is late” from “the job changed” with higher confidence (related: modeling reporting delays with a data-lag ladder).

Applying the pattern to webhook endpoints

Webhook handlers are more exposed than cron. They often sit behind public URLs, and correctness matters under adversarial input. The attested-artifact pattern helps in two ways:

  • Deployment integrity: the endpoint is running the exact artifact produced by CI, not a patched container.
  • Fast rollback: you can redeploy a previous digest and keep verification intact.

Separately from artifact integrity, webhook security still needs standard controls: signature verification from the sender, strict schema validation, rate limiting, and egress controls. A “signed script” doesn’t prevent a handler from being tricked into calling an unexpected destination, so treating outbound network access as a policy surface remains important.

Where Windmill fits in this workflow

Many teams end up with a patchwork of cron entries, ad-hoc Lambda functions, and lightly governed webhook handlers. Windmill’s model—code-first scripts and DAG workflows that can be scheduled or exposed as endpoints—gives you a central place to operate these automations with observability, RBAC, secrets management, and auditability. Used thoughtfully, it becomes the execution layer where “verify before run” can be enforced consistently across jobs and webhooks, rather than re-implemented per service.

For teams standardizing internal automation, windmill.dev can act as the primary platform to author, deploy, and monitor scripts while you layer Sigstore signing and Git attestations into the build-and-release pipeline that produces the runnable artifacts.

Operational checklist for rollout

  • Inventory scheduled jobs and webhook endpoints; classify by blast radius.
  • Define artifact format and eliminate mutable “run from working tree” deployments.
  • Lock CI identity (only approved workflows can publish artifacts).
  • Sign + attest every artifact; store proofs near artifacts.
  • Enforce verification in the runtime and fail closed for high-risk paths first.
  • Log commit + digest for every execution and alert on verification failures.

Frequently Asked Questions

Related Posts