Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1efd2bd
fix(detector): recognize quoted JSON API key fields
cemililik Aug 10, 2026
3950ed6
fix(detector): harden contextual API key matching
cemililik Aug 10, 2026
c9c68a3
fix(engine): preserve exact detector match locations
cemililik Aug 10, 2026
36957d4
feat(detector): add structured configuration secret detection
cemililik Aug 10, 2026
16230ca
fix(detector): harden structured config scanning
cemililik Aug 10, 2026
ac4cfa7
fix(detector): enforce structured scan safety contracts
cemililik Aug 10, 2026
403d03e
fix(verifier): make Grafana verification instance-aware
cemililik Aug 10, 2026
eae4d02
fix(verifier): enforce trusted Grafana verification
cemililik Aug 10, 2026
b4dce48
fix(verifier): close Grafana trust edge cases
cemililik Aug 10, 2026
a027a17
fix(verifier): make New Relic verification region-aware
cemililik Aug 10, 2026
46a2068
fix(verifier): pace regional fallback requests
cemililik Aug 10, 2026
806ef75
fix(verifier): bind request gates to engine limits
cemililik Aug 10, 2026
7a53406
feat(meta): publish truthful verification capabilities
cemililik Aug 10, 2026
eff9772
fix(meta): fail closed on issuer-dependent verification
cemililik Aug 10, 2026
86d7db1
fix(meta): make capability decisions fail conservative
cemililik Aug 10, 2026
45b739c
fix(verifier): make Twilio and Shopify context truthful
cemililik Aug 10, 2026
9841b18
fix(detector): enforce correlated credential boundaries
cemililik Aug 10, 2026
fdd507b
fix(site): fail closed on correlated detector drift
cemililik Aug 10, 2026
ce015fd
test(contracts): enforce registry-wide scan safety
cemililik Aug 10, 2026
df31b4a
fix(contracts): close registry verification trust gaps
cemililik Aug 10, 2026
fb73ab2
fix(contracts): complete registry and context guarantees
cemililik Aug 11, 2026
1c32191
feat(metadata): eliminate user-facing release drift
cemililik Aug 11, 2026
edcdc54
fix(metadata): enforce release and documentation contracts
cemililik Aug 11, 2026
5d79f7d
fix(release): validate tags and stage site generation
cemililik Aug 11, 2026
89c27e8
feat(reliability): bound validation and provider retries
cemililik Aug 11, 2026
2c19383
fix(reliability): gate fallbacks and honor cancellation
cemililik Aug 11, 2026
40e07f6
fix(reliability): enforce request and cleanup boundaries
cemililik Aug 11, 2026
604a7b5
docs: establish canonical publication contracts
cemililik Aug 11, 2026
d490590
fix(docs): close publication contract gaps
cemililik Aug 11, 2026
282dca4
fix(docs): make publication contracts transactional
cemililik Aug 11, 2026
871e7ae
feat(product): complete post-review hardening
cemililik Aug 11, 2026
847d20f
fix(product): address wave 11 review findings
cemililik Aug 11, 2026
655cc83
fix(product): close wave 11 final review gaps
cemililik Aug 11, 2026
f6e517e
refactor(quality): resolve CodeFactor findings
cemililik Aug 11, 2026
22d7f2c
fix: close pre-merge security review findings
cemililik Aug 11, 2026
5755635
chore(release): prepare v1.8.0
cemililik Aug 11, 2026
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

This file was deleted.

1 change: 1 addition & 0 deletions .github/secret_scanning.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
paths-ignore:
- "internal/detector/**/*_test.go"
- "internal/detector/generic/testdata/appsettings.synthetic.json"
- "internal/verifier/**/*_test.go"
- "internal/engine/**/*_test.go"
- "internal/source/**/*_test.go"
Expand Down
19 changes: 15 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,23 @@ jobs:
go-version: '1.25.12'
cache: true
cache-dependency-path: tools/site-build/go.sum
- name: Regenerate site/js from tools/site-build
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
- name: Test site generator and browser detector contracts
working-directory: tools/site-build
run: go test -count=1 ./...
- name: Regenerate site output from tools/site-build
working-directory: tools/site-build
run: go run . -strict
- name: Fail if the committed site/js has drifted from the generator
- name: Fail if the committed site has drifted from the generator
run: |
if ! git diff --exit-code -- site/js; then
echo "::error::site/js is stale. Run 'cd tools/site-build && go run . -strict' from the repo root and commit the regenerated files under site/js/."
if ! git diff --exit-code -- site; then
echo "::error::site output is stale. Run 'cd tools/site-build && go run . -strict' from the repo root and commit the regenerated files under site/."
exit 1
fi
if test -n "$(git status --porcelain --untracked-files=all -- site)"; then
echo "::error::site generator created untracked output. Regenerate and commit every generated file under site/."
git status --short --untracked-files=all -- site
exit 1
fi
43 changes: 43 additions & 0 deletions .github/workflows/provider-contract-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Provider Contract Audit Freshness

on:
schedule:
- cron: '17 6 * * 1'
workflow_dispatch:
push:
branches: [main]
paths:
- 'internal/meta/capabilities.go'
- 'internal/meta/capabilities_test.go'
- 'internal/meta/provider_contract_links_test.go'
- 'docs/standards/05-PROVIDER-CONTRACT-AUDITS.md'
- '.github/workflows/provider-contract-audit.yml'
pull_request:
paths:
- 'internal/meta/capabilities.go'
- 'internal/meta/capabilities_test.go'
- 'internal/meta/provider_contract_links_test.go'
- 'docs/standards/05-PROVIDER-CONTRACT-AUDITS.md'
- '.github/workflows/provider-contract-audit.yml'

permissions:
contents: read

jobs:
freshness:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: '1.25.12'
cache: true
- name: Enforce reviewed provider-contract freshness
run: go test ./internal/meta -run '^TestVerificationCapabilities_ReviewedContractsAreFresh$' -count=1
- name: Verify official provider references and anchors
env:
LEAKWATCH_CHECK_PROVIDER_LINKS: '1'
run: go test ./internal/meta -run '^TestVerificationCapabilities_ReviewedReferenceLinksResolve$' -count=1 -timeout=8m
13 changes: 13 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ jobs:
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00
with:
go-version: '1.25.12'
- name: Validate release tag, metadata, and generated site
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
set -euo pipefail
go run ./internal/meta/releasecheck --tag "$RELEASE_TAG"
go test ./internal/meta ./cmd
(
cd tools/site-build
go run . -strict
)
git diff --exit-code -- site
test -z "$(git status --porcelain --untracked-files=all -- site)"
# docker/setup-qemu-action@v3.2.0
- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/site-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
paths:
- "site/**"
- "docs/user-manuals/**"
- "internal/meta/release.go"
- "tools/site-build/**"
- ".github/workflows/site-deploy.yml"
workflow_dispatch:
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/vscode-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,14 @@ jobs:

- name: Test
run: npm test

- name: Package VSIX
run: npm run package:vsix

- name: Upload VSIX
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: leakwatch-vsix
path: vscode/leakwatch-*.vsix
if-no-files-found: error
retention-days: 14
122 changes: 122 additions & 0 deletions .github/workflows/vscode-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Publish VS Code Extension

on:
workflow_dispatch:
inputs:
publish:
description: Publish the packaged VSIX to Visual Studio Marketplace
required: true
type: boolean
default: false

permissions:
contents: read

concurrency:
group: vscode-marketplace-publish
cancel-in-progress: false

defaults:
run:
working-directory: vscode

jobs:
package:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: npm
cache-dependency-path: vscode/package-lock.json

- name: Install dependencies
run: npm ci

- name: Lint, test, and package
run: npm run lint && npm test && npm run package:vsix

- name: Upload reviewable VSIX
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: leakwatch-vsix
path: vscode/leakwatch-*.vsix
if-no-files-found: error
retention-days: 14

publish:
if: ${{ inputs.publish && github.ref == 'refs/heads/main' }}
needs: package
runs-on: ubuntu-latest
timeout-minutes: 15
environment: vscode-marketplace
permissions:
actions: read
contents: read
deployments: read
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with:
persist-credentials: false

- name: Fail closed unless Marketplace environment policy is protected
env:
GH_API_TOKEN: ${{ github.token }}
GH_ENVIRONMENT_AUDIT_TOKEN: ${{ secrets.VSCODE_ENV_AUDIT_TOKEN }}
run: |
policy_file="${RUNNER_TEMP:?}/vscode-marketplace-environment.json"
curl --fail-with-body --silent --show-error \
--header "Accept: application/vnd.github+json" \
--header @<(printf 'Authorization: Bearer %s\n' "${GH_API_TOKEN:?}") \
--header "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL:?}/repos/${GITHUB_REPOSITORY:?}/environments/vscode-marketplace" \
--output "$policy_file"
jq --exit-status '
([.protection_rules[]?
| select(.type == "required_reviewers" and .prevent_self_review == true)
| .reviewers[]?] | length) >= 1
and .deployment_branch_policy.protected_branches == true
' "$policy_file" >/dev/null

secret_metadata_file="${RUNNER_TEMP:?}/vscode-marketplace-vsce-pat.json"
curl --fail-with-body --silent --show-error \
--header "Accept: application/vnd.github+json" \
--header @<(printf 'Authorization: Bearer %s\n' "${GH_ENVIRONMENT_AUDIT_TOKEN:?}") \
--header "X-GitHub-Api-Version: 2022-11-28" \
"${GITHUB_API_URL:?}/repos/${GITHUB_REPOSITORY:?}/environments/vscode-marketplace/secrets/VSCE_PAT" \
--output "$secret_metadata_file"
jq --exit-status '.name == "VSCE_PAT"' "$secret_metadata_file" >/dev/null

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: npm
cache-dependency-path: vscode/package-lock.json

- name: Install dependencies
run: npm ci

- name: Download reviewed VSIX
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: leakwatch-vsix
path: vscode/artifact

- name: Publish reviewed VSIX
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
run: |
: "${VSCE_PAT:?missing environment-scoped VSCE_PAT}"
mapfile -t packages < <(find artifact -type f -name 'leakwatch-*.vsix' -print)
if [[ ${#packages[@]} -ne 1 ]]; then
echo "expected exactly one VSIX artifact" >&2
exit 1
fi
npx --no-install vsce publish --packagePath "${packages[0]}"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ vendor/
# IDE
.idea/
.vscode/
.claude/
*.swp
*.swo
*~
Expand All @@ -30,6 +31,7 @@ Thumbs.db

# Code Reviews
docs/code-reviews/
review/

# Marketing (internal, not published)
docs/marketing/
Expand Down
4 changes: 4 additions & 0 deletions .leakwatchignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# These are NOT real secrets — they are fixtures that match regex patterns.
**/*_test.go

# This fixture contains deterministic, synthetic, intentionally matchable
# credentials. Keep the exemption exact so future testdata remains scanned.
internal/detector/generic/testdata/appsettings.synthetic.json

# Verifier implementations contain API URL patterns that may match detectors.
internal/verifier/**

Expand Down
42 changes: 40 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

_Nothing yet._
## [v1.8.0] - 2026-08-11

### Added

- A default-on `structured-config-secret` detector for JSON, YAML, TOML, INI,
dotenv, and XML configuration values, bringing the catalog to **65
detectors**. It can be disabled explicitly with
`--exclude-detectors structured-config-secret`.
- Repeatable `--verifier-origin detector-id=https://host` routing for
operator-trusted verifier targets, plus the backward-compatible
`--grafana-instance-url` alias.
- Opt-in Slack text-attachment scanning with Slack-owned HTTPS enforcement,
operation-scoped request limiting, byte-bounded backpressure, bounded file
size/retries, UTF-8 text classification, token-safe errors/logs, and file-ID
de-duplication.
- Best-effort GitHub scope/expiration and GitLab PAT standard or GitLab 19.2+ granular scope/expiration metadata
after authoritative active verification.
- A reviewable VSIX artifact, 256×256 Marketplace icon, main-only manual VS Code
publication workflow with executable environment-policy and environment-secret
provenance audits, and a scheduled provider-contract freshness/link gate.

### Changed

- Auth0, Datadog, GitHub, GitHub OAuth, GitLab, Grafana, Shopify, Snyk, and
Twilio verification now requires an explicit operator-trusted origin. Without
one, Leakwatch sends no credential and reports the finding as `unverified`.
- Slack's `--rate-limit` default changed from `1` to `0`; zero preserves the
provider-safe, operation-specific limits instead of imposing one global
request rate on every Slack method.
- Source cleanup or partial-scan failures are now visible and non-clean. A
cleanup failure without findings exits `2`; partial results still exit `1`
while retaining and reporting the source error.
- Finding JSON now distinguishes calculated zero entropy from absent entropy and
omits an unset detection timestamp; terminal tables use Unicode display width,
visibly escape bidi controls, and render `--show-raw` as a reversible quoted
value instead of passing terminal controls through or dropping secret bytes.
- Detector/verifier registries fail closed on invalid or duplicate registration,
matcher results are explicitly stable, and obsolete global custom-rule APIs
were removed.

---

## [v1.7.0] - 2026-07-19
## [v1.7.0] - 2026-07-20

> A comprehensive, multi-dimensional review of the entire project (code, tests, docs, CI/CD, VS Code extension, and website) was completed and its findings remediated across the changes below.

Expand Down
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ Architecture decisions are documented in ADR format under `docs/decisions/`. The
| [ADR-0002](docs/decisions/ADR-0002-cli-frame.md) | Cobra + Viper | Nested commands, hierarchical configuration |
| [ADR-0003](docs/decisions/ADR-0003-git-library.md) | go-git | Pure Go, no CGO, no external dependencies |
| [ADR-0004](docs/decisions/ADR-0004-plugin-architecture.md) | Compile-time registration | init() + blank import, type-safe |
| [ADR-0005](docs/decisions/ADR-0005-pattern-matching.md) | Aho-Corasick hybrid | AC pre-filter → regex validation → entropy |
| [ADR-0005](docs/decisions/ADR-0005-pattern-matching.md) | Aho-Corasick hybrid | Entropy clause amended; AC pre-filter → regex validation remains active |
| [ADR-0006](docs/decisions/ADR-0006-container-library.md) | go-containerregistry | Daemonless, layer-based analysis |
| [ADR-0007](docs/decisions/ADR-0007-license.md) | MIT | Enterprise adoption, open-core compatibility |
| [ADR-0008](docs/decisions/ADR-0008-concurrency-model.md) | Worker Pool | Fixed worker count, channel-based |
| [ADR-0009](docs/decisions/ADR-0009-github-marketplace-action.md) | Marketplace Action | Root `action.yml`, prebuilt-binary composite, `@v1` |
| [ADR-0010](docs/decisions/ADR-0010-entropy-gating-policy.md) | Entropy gating | Threshold gates opt-in heuristic findings only |

## Coding Standards

Expand Down Expand Up @@ -124,6 +125,11 @@ Full standards: [docs/standards/04-DEVELOPMENT-STANDARDS.md](docs/standards/04-D
Types: feat, fix, docs, test, refactor, perf, ci, chore
```

Before every commit, review the documentation surfaces affected by the change
(including README, changelog, roadmap, guides, user manuals, and generated site
artifacts). A commit must not knowingly leave product behavior, counts, versions,
or capability claims stale.

**Examples:**
```
feat(detector): add AWS Secret Access Key detector
Expand Down
Loading
Loading