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
16 changes: 15 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,21 @@ jobs:
# Dependabot-authored runs get a secrets-restricted GITHUB_TOKEN and
# cannot see repo Actions secrets (only the separate Dependabot secrets
# store, which SONAR_TOKEN isn't in) -- skip rather than fail unwinnably.
if: github.actor != 'dependabot[bot]'
#
# `vars.SONAR_ENABLED` makes the scan opt-in. This is NOT a way to hide a
# real quality finding: the scan currently fails with HTTP 403 Forbidden
# while fetching JRE metadata, i.e. it never authenticates and never
# analyses anything. That is a credential/project-binding fault needing an
# owner action (rotate SONAR_TOKEN and confirm the SonarCloud binding for
# hyperpolymath_boj-server-cartridges), not a YAML defect — the YAML is
# otherwise clean. A permanently-red check that no contributor can fix is
# itself noise, and it masks genuine reds on main.
#
# TO RE-ENABLE once the token is rotated: set repository variable
# SONAR_ENABLED=true (Settings -> Secrets and variables -> Actions ->
# Variables). Gating on `vars.` is deliberate; `secrets.*` is unavailable
# in `if:` expression context and is the estate compile-error anti-pattern.
if: github.actor != 'dependabot[bot]' && vars.SONAR_ENABLED == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/governance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ permissions:
contents: read
jobs:
governance:
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@d7c22711e830e1f383846472f6e9b99debdb201e
uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@c65436ee3351cd6b0fa14b142938b195efc77586
16 changes: 15 additions & 1 deletion .github/workflows/pages-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,21 @@ jobs:
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Deploy site/ to Cloudflare Pages
run: npx wrangler@latest pages deploy site/ --project-name=boj-server-cartridges
# Self-gate in the shell, not in an `if:`. Gating a job/step `if:` on
# `secrets.*` is the estate compile-error anti-pattern — secrets are
# not available in `if:` expression context. Hoisting the secret into
# `env:` and testing it in bash is the supported way to degrade to a
# green no-op when the deployment is not configured, and it is the
# same shape boj-build.yml uses to self-gate on BOJ_URL.
run: |
set -euo pipefail
if [ -z "${CLOUDFLARE_API_TOKEN:-}" ] || [ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ]; then
echo "Cloudflare Pages deployment is not configured for this repository."
echo "Set the CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets to enable it."
echo "Skipping (not a failure)."
exit 0
fi
npx wrangler@latest pages deploy site/ --project-name=boj-server-cartridges
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
9 changes: 5 additions & 4 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: MPL-2.0
name: GitHub Pages (Ddraig SSG)
on:
push:
Expand All @@ -18,9 +19,9 @@ jobs:
image: ghcr.io/stefan-hoeck/idris2-pack@sha256:f0758996a931fb35d9ecb1de273c4d59dabe2a09b433afc7e357f65a08b7e1ff
steps:
- name: Checkout Site
uses: actions/checkout@v7
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Checkout Ddraig SSG
uses: actions/checkout@v7
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: hyperpolymath/ddraig-ssg
path: .ddraig-ssg
Expand All @@ -37,7 +38,7 @@ jobs:
fi
./.ddraig-ssg/build/exec/ddraig build src _site https://hyperpolymath.github.io/${GITHUB_REPOSITORY#*/}
- name: Upload artifact
uses: actions/upload-pages-artifact@v5
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: '_site'
deploy:
Expand All @@ -50,4 +51,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ jobs:
contents: read
security-events: write
id-token: write
uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@d7c22711e830e1f383846472f6e9b99debdb201e
uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@c65436ee3351cd6b0fa14b142938b195efc77586
secrets: inherit
7 changes: 4 additions & 3 deletions .github/workflows/secret-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ permissions:
contents: read
jobs:
scan:
# The post-#500 reusable runs gitleaks as a pinned, checksum-verified
# binary rather than via gitleaks-action, so it no longer needs
# `pull-requests: write` or `actions: read`. Narrowed to least privilege.
permissions:
contents: read
pull-requests: write
actions: read
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@d135b05bfc647d0c0fbfedc7e80f37ea50f49236
uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@c65436ee3351cd6b0fa14b142938b195efc77586
secrets: inherit
trufflehog:
runs-on: ubuntu-latest
Expand Down
105 changes: 105 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# SPDX-License-Identifier: MPL-2.0
#
# Gitleaks configuration — estate baseline.
#
# WHY THIS FILE EXISTS
# --------------------
# Until #500 the estate's gitleaks step carried `continue-on-error: true`, so
# the primary secret scanner could not fail a PR. #500 made it gate for real
# (`gitleaks detect --exit-code 1` against a checksum-verified binary). The
# first honest run then surfaced 15 findings in this repo — every one a false
# positive: module integrity hashes, package UUIDs, a public GPG fingerprint,
# a Haskell type *name*, and synthetic `.example` fixtures.
#
# That is very likely the trap the `continue-on-error` was papering over: turn
# the gate on with no allowlist, get a wall of red that is entirely noise,
# someone reverts, and the estate is back to a scanner that cannot fail. This
# config is therefore the *unblocker* for re-pinning callers onto the real
# gate across the estate.
#
# DESIGN RULE — KEEP THIS WHEN EDITING
# ------------------------------------
# Allowlist by PATTERN CLASS, anchored to the WHOLE value. Never allowlist a
# path wholesale because "that file is fine", and never disable a rule.
#
# Every `regexes` entry below is anchored `^...$` on purpose. An unanchored
# entry is a substring match, which silently blinds the scanner: a pattern
# like `(?i)test|example` would allowlist the real AWS key
# `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` purely because "EXAMPLE" appears
# inside it. That was caught by canary-testing an earlier draft of this file —
# if you add a pattern here, plant a realistic secret and confirm it is still
# detected before you commit.
#
# `paths` entries are limited to formats that cannot legitimately hold a live
# credential (lockfile integrity hashes, dependency UUIDs). If you want to
# allowlist any other path wholesale, that is a signal the secret should be
# removed from the tree instead.

[extend]
useDefault = true

[allowlist]
description = "Estate baseline: dependency metadata, anchored placeholder shapes, published test vectors"

paths = [
# Lockfiles: the "secrets" are SHA-256 *integrity hashes* of public registry
# modules. A lockfile has no legitimate reason to contain a credential.
'''(^|/)deno\.lock$''',
'''(^|/)package-lock\.json$''',
'''(^|/)yarn\.lock$''',
'''(^|/)Cargo\.lock$''',
# Julia project manifests: entries are public package UUIDs from the General
# registry, which trip the generic-api-key entropy heuristic.
'''(^|/)Project\.toml$''',
'''(^|/)Manifest\.toml$''',
]

regexes = [
# --- documented placeholder shapes (all anchored to the whole value) ------

# Ellipsis-terminated illustrative values: `abc123def456...` (carrying an
# explicit "// Would be real token" comment), `1234567890_abc123...` inside a
# fenced ASCII mockup of terminal output. A real credential is never elided.
'''^[A-Za-z0-9_\-]{4,}\.\.\.$''',

# Repeated-character masks: a provider prefix followed by a long run of a
# single filler character (the GitLab, GitHub and OpenAI token prefixes are
# all commonly masked this way in docs). A real credential never repeats one
# character 8+ times.
#
# Deliberately described rather than shown: writing the masked token out
# literally here makes THIS file trip the estate's Hypatia secret detector
# ("Secret found: GitLab PAT"), which is how that was found. Do not add
# literal example tokens to this file, even inside comments.
'''^[A-Za-z0-9_\-]*?(x{8,}|X{8,}|y{8,}|z{8,}|0{12,}|\*{6,})[A-Za-z0-9_\-]*$''',

# Monotonic hex walks used as filler: `0123456789abcdef` repeated,
# `ABCDEF0123456789ABCDEF0123456789`, `0a1b2c3d4e5f6a7b…` (ascending nibble
# pairs). These are keyboard-walk fillers, never generated key material.
'''^(?i:0123456789abcdef|abcdef0123456789|0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1|deadbeef|cafebabe)+$''',

# Snake-case self-labelled fixtures, e.g. `sg_test_api_key_abc123`. Anchored
# and shape-constrained: an all-lowercase snake_case string with an explicit
# test/demo marker as a bounded segment. Real API keys carry mixed case,
# digits and symbols and will not match this.
'''^[a-z]{2,6}_(test|demo|fake|sample|example|dummy|placeholder)_[a-z0-9_]{2,40}$''',

# --- published test vectors ----------------------------------------------
# RFC 8032 §7.1 TEST 1 Ed25519 seed and the public key it derives. These
# exact values are printed in the RFC; checking that one yields the other is
# the entire point of the interoperability test.
'''^9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60$''',
'''^d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a$''',

# --- public-by-definition / non-secret identifiers ------------------------
# OpenPGP 40-hex fingerprints. A fingerprint *identifies* a key; it is
# published deliberately (SECURITY.md, audit records, keyservers) and
# discloses nothing. Secret key *material* is PEM-armoured and is caught by
# the dedicated private-key rules, which are NOT allowlisted here.
'''^[A-F0-9]{40}$''',

# Cryptographic *type names* appearing in source/design docs, e.g. the
# Haskell declaration `data Ed25519KeyPair = Ed25519KeyPair`. A bare
# CamelCase identifier with no digits or separators is a type, not a key.
'''^(Ed25519|X25519|Curve25519|RSA|ECDSA|EdDSA|Secp256k1)[A-Za-z]*$''',
]
Loading