Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/trigger-deploy
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
2026-07-17T17:20:00Z deploy manifest-merge + alias collapse
2026-07-17T18:00:00Z deploy price tiebreak
2026-07-18T02:00:00Z deploy wish-bridge qualified-demand gate
2026-07-18T02:45:00Z deploy operator demand board
38 changes: 38 additions & 0 deletions .github/workflows/secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Always-on secret scanning. Unlike deploy.yml (marker-gated), this runs on
# EVERY push to a tracked branch and EVERY pull request — a committed
# credential should never depend on remembering a marker. gitleaks scans the
# working tree against its default high-signal ruleset (OpenAI sk- keys,
# GitHub/AWS tokens, private keys, mnemonics, ...) plus the repo allowlist in
# .gitleaks.toml, which suppresses this repo's structural false positives
# (public on-chain addresses, the demo JWT, test canaries). Only a genuinely
# new secret fails the job.
name: secret-scan

on:
push:
branches: ["claude/sweet-brown-i99jl3", "main"]
pull_request:

permissions:
contents: read

jobs:
gitleaks:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd
- name: Scan for committed secrets (gitleaks, pinned + checksum-verified)
env:
GITLEAKS_VERSION: "8.21.2"
run: |
set -euo pipefail
FN="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
BASE="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}"
curl -sSL --fail -o "/tmp/${FN}" "${BASE}/${FN}"
curl -sSL --fail -o /tmp/gitleaks_checksums.txt "${BASE}/gitleaks_${GITLEAKS_VERSION}_checksums.txt"
( cd /tmp && grep " ${FN}\$" gitleaks_checksums.txt | sha256sum -c - )
tar -xzf "/tmp/${FN}" -C /tmp gitleaks
# Tree scan (--no-git): fails the job on any finding not allowlisted
# in .gitleaks.toml. --redact keeps any match out of the public logs.
/tmp/gitleaks detect --no-git --config .gitleaks.toml --redact --verbose
39 changes: 39 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# gitleaks config for Agent402. Extends the default ruleset (which catches
# real high-signal secrets: OpenAI sk- keys, GitHub tokens, AWS keys, private
# keys, mnemonics, etc.) and allowlists the structural false positives this
# repo carries by design, so CI stays green until a GENUINELY new secret lands.
#
# Every allowlist entry below was verified against a full-tree + full-history
# scan (2026-07-18): all pre-existing hits are public on-chain addresses, the
# standard demo JWT, or fake test/canary fixtures. Real secrets live only in
# Railway env and GitHub Actions secrets, never in the repo.
[extend]
useDefault = true

[allowlist]
description = "Agent402 known false positives: on-chain addresses, demo JWTs, test fixtures"
# Fixtures and copy that intentionally contain fake or public credential-shaped
# strings. Test files assert on canaries by design; docs carry example tokens.
paths = [
'''scripts/test-.*\.js''',
'''docs/.*''',
'''package-lock\.json''',
'''\.gitleaks\.toml''',
]
# Matched against each finding's captured secret.
regexes = [
# EVM contract/wallet addresses are public identifiers, never secrets. This
# is 40 hex chars precisely; a real EVM private key is 64 hex and is NOT
# covered here, so it would still fire.
'''0x[0-9a-fA-F]{40}\b''',
# The leak-guard test's own canary tokens (e.g. fredv2-LEAKCANARY0000).
'''LEAKCANARY''',
# Placeholder KDF-output example in the crypto-hash tool docs.
'''a1b2c3d4e5f6''',
]
# The standard demo JWT ({"alg":"HS256","typ":"JWT"} header) used as the
# decode-jwt tool's worked example in kit.js / kit2.js / skills.js. Stopwords
# match when the secret contains the substring.
stopwords = [
'''eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9''',
]