Skip to content

ci(deps): add dependency-review PR gate#983

Merged
oskarszoon merged 2 commits into
bsv-blockchain:mainfrom
oskarszoon:feat/dependency-check-ci-gate
May 29, 2026
Merged

ci(deps): add dependency-review PR gate#983
oskarszoon merged 2 commits into
bsv-blockchain:mainfrom
oskarszoon:feat/dependency-check-ci-gate

Conversation

@oskarszoon

@oskarszoon oskarszoon commented May 29, 2026

Copy link
Copy Markdown
Contributor

What

Adds one blocking CI gate: dependency-review on every PR. Fails a PR that adds a dependency with a ≥ high-severity CVE or a disallowed licence (GPL-2.0/3.0, AGPL-3.0). Diff-scoped — only the PR's added/changed deps, so it never trips on the existing backlog.

Native Dependabot alerts notify on vulnerable deps but don't block merges — this enforces. That's the one gap in teranode's enterprise security stack.

Why just this

teranode's enterprise policy already provides, zero-config:

  • Dependabot alerts (known CVEs) + Dependabot malware (catalogued malicious packages)
  • Code scanning (first-party vulns) + secret scanning

Evaluated and dropped as redundant / low-value:

  • OSV-Scanner — same known-CVE coverage as Dependabot alerts.
  • govulncheck — only adds reachability triage over Dependabot's Go alerts; no new detection.
  • guarddog — native Dependabot malware covers catalogued malware; its Go typosquatting heuristic false-positives on Go /vN module paths (validated against this repo's deps).
  • AI reviewer / Socket.dev — deferred (residual gap: novel uncatalogued malware).

Action needed after merge

Add dependency-review as a required status check in branch protection for main (Settings ▸ Branches) — that's what makes it enforce.

Notes

dependency-review-action pinned by commit SHA. The clean-PR run passes; blocking on a bad dep follows the action's standard behaviour (not exercised in this PR).

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-983 (0ead615)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 144
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.802µ 1.801µ ~ 1.000
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 61.50n 61.40n ~ 0.700
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 61.62n 61.81n ~ 1.000
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 61.39n 61.62n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 35.81n 34.12n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 64.01n 56.32n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 202.3n 135.4n ~ 0.100
MiningCandidate_Stringify_Short-4 265.4n 262.2n ~ 0.100
MiningCandidate_Stringify_Long-4 2.013µ 1.948µ ~ 0.100
MiningSolution_Stringify-4 1024.0n 990.2n ~ 0.100
BlockInfo_MarshalJSON-4 1.906µ 1.835µ ~ 0.100
NewFromBytes-4 133.3n 133.0n ~ 1.000
AddTxBatchColumnar_Validation-4 2.540µ 2.615µ ~ 1.000
OffsetValidationLoop-4 638.0n 636.9n ~ 0.700
Mine_EasyDifficulty-4 61.22µ 61.40µ ~ 0.400
Mine_WithAddress-4 6.868µ 7.209µ ~ 0.700
DirectSubtreeAdd/4_per_subtree-4 62.15n 59.35n ~ 1.000
DirectSubtreeAdd/64_per_subtree-4 29.32n 29.86n ~ 0.100
DirectSubtreeAdd/256_per_subtree-4 28.32n 28.89n ~ 0.100
DirectSubtreeAdd/1024_per_subtree-4 27.30n 27.84n ~ 0.100
DirectSubtreeAdd/2048_per_subtree-4 26.91n 27.38n ~ 0.100
SubtreeProcessorAdd/4_per_subtree-4 285.0n 283.7n ~ 0.400
SubtreeProcessorAdd/64_per_subtree-4 279.7n 276.8n ~ 0.400
SubtreeProcessorAdd/256_per_subtree-4 279.8n 281.0n ~ 0.100
SubtreeProcessorAdd/1024_per_subtree-4 268.6n 268.5n ~ 0.600
SubtreeProcessorAdd/2048_per_subtree-4 269.8n 268.1n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 276.6n 275.7n ~ 0.800
SubtreeProcessorRotate/64_per_subtree-4 274.7n 274.2n ~ 0.700
SubtreeProcessorRotate/256_per_subtree-4 274.7n 274.3n ~ 0.400
SubtreeProcessorRotate/1024_per_subtree-4 273.2n 271.1n ~ 0.100
SubtreeNodeAddOnly/4_per_subtree-4 54.79n 54.52n ~ 0.100
SubtreeNodeAddOnly/64_per_subtree-4 34.30n 34.32n ~ 0.700
SubtreeNodeAddOnly/256_per_subtree-4 33.37n 33.33n ~ 1.000
SubtreeNodeAddOnly/1024_per_subtree-4 32.53n 32.45n ~ 1.000
SubtreeCreationOnly/4_per_subtree-4 113.3n 113.5n ~ 0.400
SubtreeCreationOnly/64_per_subtree-4 401.4n 405.5n ~ 0.200
SubtreeCreationOnly/256_per_subtree-4 1.378µ 1.370µ ~ 0.700
SubtreeCreationOnly/1024_per_subtree-4 4.455µ 4.483µ ~ 0.400
SubtreeCreationOnly/2048_per_subtree-4 8.184µ 8.201µ ~ 0.700
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 272.5n 275.0n ~ 0.400
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 273.6n 274.0n ~ 0.700
ParallelGetAndSetIfNotExists/1k_nodes-4 2.212m 2.207m ~ 1.000
ParallelGetAndSetIfNotExists/10k_nodes-4 5.481m 5.352m ~ 0.100
ParallelGetAndSetIfNotExists/50k_nodes-4 7.449m 7.355m ~ 0.100
ParallelGetAndSetIfNotExists/100k_nodes-4 9.952m 10.173m ~ 0.400
SequentialGetAndSetIfNotExists/1k_nodes-4 1.959m 1.941m ~ 0.200
SequentialGetAndSetIfNotExists/10k_nodes-4 4.458m 4.386m ~ 0.400
SequentialGetAndSetIfNotExists/50k_nodes-4 12.21m 13.34m ~ 0.100
SequentialGetAndSetIfNotExists/100k_nodes-4 22.09m 23.21m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 2.272m 2.242m ~ 0.200
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 8.311m 8.305m ~ 1.000
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 13.24m 13.22m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 1.992m 1.973m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 7.530m 7.985m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 39.53m 40.43m ~ 0.100
BlockAssembler_AddTx-4 0.02255n 0.02184n ~ 0.400
AddNode-4 9.179 8.812 ~ 0.400
AddNodeWithMap-4 8.942 9.299 ~ 0.400
DiskTxMap_SetIfNotExists-4 3.902µ 3.768µ ~ 0.100
DiskTxMap_SetIfNotExists_Parallel-4 3.563µ 3.468µ ~ 0.700
DiskTxMap_ExistenceOnly-4 321.7n 317.7n ~ 0.100
Queue-4 187.7n 187.0n ~ 0.200
AtomicPointer-4 3.627n 3.648n ~ 0.400
ReorgOptimizations/DedupFilterPipeline/Old/10K-4 869.5µ 863.3µ ~ 0.400
ReorgOptimizations/DedupFilterPipeline/New/10K-4 784.9µ 782.1µ ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/10K-4 119.6µ 107.8µ ~ 0.100
ReorgOptimizations/AllMarkFalse/New/10K-4 64.14µ 64.08µ ~ 0.400
ReorgOptimizations/HashSlicePool/Old/10K-4 60.32µ 54.88µ ~ 0.700
ReorgOptimizations/HashSlicePool/New/10K-4 11.17µ 10.96µ ~ 0.100
ReorgOptimizations/NodeFlags/Old/10K-4 4.954µ 5.031µ ~ 0.700
ReorgOptimizations/NodeFlags/New/10K-4 2.145µ 1.962µ ~ 0.100
ReorgOptimizations/DedupFilterPipeline/Old/100K-4 9.381m 9.202m ~ 0.400
ReorgOptimizations/DedupFilterPipeline/New/100K-4 9.390m 9.147m ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/100K-4 1.085m 1.085m ~ 1.000
ReorgOptimizations/AllMarkFalse/New/100K-4 708.1µ 707.5µ ~ 1.000
ReorgOptimizations/HashSlicePool/Old/100K-4 530.0µ 462.0µ ~ 0.100
ReorgOptimizations/HashSlicePool/New/100K-4 212.4µ 208.5µ ~ 0.400
ReorgOptimizations/NodeFlags/Old/100K-4 48.60µ 51.61µ ~ 0.200
ReorgOptimizations/NodeFlags/New/100K-4 17.06µ 17.84µ ~ 0.100
TxMapSetIfNotExists-4 49.45n 50.30n ~ 0.100
TxMapSetIfNotExistsDuplicate-4 41.25n 41.58n ~ 0.200
ChannelSendReceive-4 611.3n 590.8n ~ 0.100
CalcBlockWork-4 473.8n 471.9n ~ 0.400
CalculateWork-4 648.2n 647.6n ~ 0.400
BuildBlockLocatorString_Helpers/Size_10-4 1.362µ 1.361µ ~ 0.500
BuildBlockLocatorString_Helpers/Size_100-4 13.10µ 13.01µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 152.2µ 130.5µ ~ 0.400
CatchupWithHeaderCache-4 104.5m 104.7m ~ 0.700
_prepareTxsPerLevel-4 436.1m 515.0m ~ 0.200
_prepareTxsPerLevelOrdered-4 4.940m 4.666m ~ 0.200
_prepareTxsPerLevel_Comparison/Original-4 459.0m 427.2m ~ 0.700
_prepareTxsPerLevel_Comparison/Optimized-4 3.901m 5.172m ~ 0.400
SubtreeSizes/10k_tx_4_per_subtree-4 1.376m 1.373m ~ 1.000
SubtreeSizes/10k_tx_16_per_subtree-4 321.5µ 330.0µ ~ 0.200
SubtreeSizes/10k_tx_64_per_subtree-4 77.12µ 78.32µ ~ 0.100
SubtreeSizes/10k_tx_256_per_subtree-4 19.31µ 19.50µ ~ 0.100
SubtreeSizes/10k_tx_512_per_subtree-4 9.632µ 9.752µ ~ 0.400
SubtreeSizes/10k_tx_1024_per_subtree-4 4.772µ 4.830µ ~ 0.100
SubtreeSizes/10k_tx_2k_per_subtree-4 2.378µ 2.394µ ~ 0.400
BlockSizeScaling/10k_tx_64_per_subtree-4 75.81µ 77.21µ ~ 0.100
BlockSizeScaling/10k_tx_256_per_subtree-4 19.09µ 19.43µ ~ 0.100
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.761µ 4.797µ ~ 0.400
BlockSizeScaling/50k_tx_64_per_subtree-4 399.5µ 408.9µ ~ 0.100
BlockSizeScaling/50k_tx_256_per_subtree-4 95.52µ 97.80µ ~ 0.200
BlockSizeScaling/50k_tx_1024_per_subtree-4 23.33µ 23.90µ ~ 0.100
SubtreeAllocations/small_subtrees_exists_check-4 160.2µ 162.6µ ~ 0.400
SubtreeAllocations/small_subtrees_data_fetch-4 165.7µ 168.0µ ~ 0.100
SubtreeAllocations/small_subtrees_full_validation-4 328.7µ 336.4µ ~ 0.100
SubtreeAllocations/medium_subtrees_exists_check-4 9.405µ 9.618µ ~ 0.400
SubtreeAllocations/medium_subtrees_data_fetch-4 9.899µ 10.013µ ~ 0.100
SubtreeAllocations/medium_subtrees_full_validation-4 19.18µ 19.85µ ~ 0.100
SubtreeAllocations/large_subtrees_exists_check-4 2.258µ 2.269µ ~ 0.400
SubtreeAllocations/large_subtrees_data_fetch-4 2.410µ 2.443µ ~ 0.700
SubtreeAllocations/large_subtrees_full_validation-4 4.799µ 4.881µ ~ 0.100
_BufferPoolAllocation/16KB-4 3.817µ 3.899µ ~ 0.700
_BufferPoolAllocation/32KB-4 8.632µ 10.496µ ~ 0.400
_BufferPoolAllocation/64KB-4 20.47µ 16.28µ ~ 0.100
_BufferPoolAllocation/128KB-4 34.30µ 34.36µ ~ 1.000
_BufferPoolAllocation/512KB-4 125.0µ 105.0µ ~ 0.100
_BufferPoolConcurrent/32KB-4 19.24µ 18.71µ ~ 0.400
_BufferPoolConcurrent/64KB-4 29.79µ 29.39µ ~ 0.400
_BufferPoolConcurrent/512KB-4 141.2µ 143.5µ ~ 0.200
_SubtreeDeserializationWithBufferSizes/16KB-4 687.3µ 688.5µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/32KB-4 700.2µ 701.2µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/64KB-4 710.4µ 711.4µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/128KB-4 719.7µ 705.8µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 600.3µ 639.9µ ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/16KB-4 36.46m 36.74m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/32KB-4 36.69m 36.75m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/64KB-4 36.71m 36.53m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/128KB-4 36.23m 36.23m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/512KB-4 36.35m 35.88m ~ 0.200
_PooledVsNonPooled/Pooled-4 831.1n 833.0n ~ 0.800
_PooledVsNonPooled/NonPooled-4 7.375µ 8.605µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 6.629µ 7.112µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.366µ 10.172µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 8.811µ 9.365µ ~ 0.200
StoreBlock_Sequential/BelowCSVHeight-4 317.9µ 317.6µ ~ 1.000
StoreBlock_Sequential/AboveCSVHeight-4 320.4µ 333.0µ ~ 1.000
GetUtxoHashes-4 258.9n 256.7n ~ 0.200
GetUtxoHashes_ManyOutputs-4 43.38µ 43.37µ ~ 1.000
_NewMetaDataFromBytes-4 230.7n 231.9n ~ 0.200
_Bytes-4 403.7n 402.7n ~ 0.700
_MetaBytes-4 137.8n 138.8n ~ 0.700

Threshold: >10% with p < 0.05 | Generated: 2026-05-29 16:58 UTC

@oskarszoon oskarszoon force-pushed the feat/dependency-check-ci-gate branch from adb1cdf to 4a6ec39 Compare May 29, 2026 10:44
@oskarszoon oskarszoon changed the title ci(deps): dependency supply-chain gate ci(deps): add dependency-review PR gate May 29, 2026
@oskarszoon oskarszoon force-pushed the feat/dependency-check-ci-gate branch from 4a6ec39 to 7fec149 Compare May 29, 2026 10:48
@oskarszoon oskarszoon marked this pull request as ready for review May 29, 2026 10:51
@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete

Current Review:

This PR adds a solid dependency review workflow as a PR gate. The implementation is secure and follows best practices:

Strengths:

  • Pinned actions by SHA for supply chain security
  • Minimal permissions (read-only default, job-level elevation)
  • Diff-scoped to avoid blocking on existing backlog
  • Clear inline documentation explaining the SPDX license variant issue
  • Comprehensive license coverage for GPL/AGPL variants

One observation:

The PR description notes that dependency-review must be added as a required status check in branch protection after merge. This is a manual post-merge step. Consider documenting this in the workflow comments or CONTRIBUTING.md so future maintainers know this workflow requires branch protection configuration to enforce.

@oskarszoon oskarszoon self-assigned this May 29, 2026
@oskarszoon oskarszoon requested a review from sugh01 May 29, 2026 16:18
@ordishs

ordishs commented May 29, 2026

Copy link
Copy Markdown
Collaborator

SPDX License Identifier Coverage

The deny list uses deprecated short-form SPDX identifiers:

deny-licenses: GPL-2.0, GPL-3.0, AGPL-3.0

SPDX deprecated these in favour of explicit variants. A dependency declaring GPL-3.0-only or GPL-3.0-or-later (the current canonical forms) could potentially slip through if the action does strict matching.

Consider expanding to cover all variants:

deny-licenses: >-
  GPL-2.0-only, GPL-2.0-or-later,
  GPL-3.0-only, GPL-3.0-or-later,
  AGPL-3.0-only, AGPL-3.0-or-later

Worth verifying whether dependency-review-action normalises deprecated IDs automatically — if it does, the current list is fine.

@oskarszoon

Copy link
Copy Markdown
Contributor Author

@ordishs verified against v5.0.0 src/licenses.ts: matching is spdx.satisfiesAny with no normalisation of deprecated IDs, and anything it can't resolve is silently bucketed as "unresolved" — not denied, not warned. So GPL-3.0-only / -or-later could slip past a bare GPL-3.0.

Fixed in b6d7ad4d3 — deny-list now lists deprecated + both explicit variants per family:

GPL-2.0, GPL-2.0-only, GPL-2.0-or-later,
GPL-3.0, GPL-3.0-only, GPL-3.0-or-later,
AGPL-3.0, AGPL-3.0-only, AGPL-3.0-or-later

@sonarqubecloud

Copy link
Copy Markdown

@ordishs ordishs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved.

Verified both action pins by SHA: dependency-review-action is exactly v5.0.0 (latest v5 release), and checkout is v4.3.0 — the same SHA already used in docs-deploy.yml / claude-code-review.yml. Least-privilege permissions, correct use of pull_request (not pull_request_target), and the SPDX deny-list comment documents a real gotcha worth keeping.

Two operational notes (not code changes):

  • Add dependency-review as a required status check in branch protection, or it runs without blocking (already called out in the description).
  • Given the fork-based dev workflow, comment-summary-in-pr won't post on fork PRs (read-only token caps pull-requests: write). The gate still enforces via the check status — results just surface in the Checks tab rather than an inline comment. Correct security tradeoff; worth a line in team docs.

@oskarszoon oskarszoon merged commit c61bf46 into bsv-blockchain:main May 29, 2026
28 checks passed
@oskarszoon oskarszoon deleted the feat/dependency-check-ci-gate branch May 29, 2026 17:39
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.

3 participants