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
10 changes: 8 additions & 2 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,11 @@ packages/helpers/ @sirdeggen @ty-everett @BraydenL
# Conformance runner
conformance/ @sirdeggen @ty-everett @BraydenLangley @tonesnotes

# CI / release / repo config
.github/ @sirdeggen
# CI, release, dependency, and analysis controls require redundant ownership.
.github/ @sirdeggen @ty-everett
/package.json @sirdeggen @ty-everett
/pnpm-lock.yaml @sirdeggen @ty-everett
/pnpm-workspace.yaml @sirdeggen @ty-everett
/sonar-project.properties @sirdeggen @ty-everett
/.sonarcloud.properties @sirdeggen @ty-everett
/codecov.yml @sirdeggen @ty-everett
114 changes: 58 additions & 56 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,71 +1,73 @@
version: 2

# One coordinated version-maintenance PR per month. This is the closest
# supported cadence to the requested "about every three weeks", and the open
# limit plus automatic rebasing prevents a new queue from forming behind it.
multi-ecosystem-groups:
monthly-stack-maintenance:
schedule:
interval: monthly
time: '06:00'
timezone: America/Los_Angeles
labels:
- dependencies
commit-message:
prefix: chore(deps)
pull-request-branch-name:
separator: '-'

updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 10
patterns:
- '*'
multi-ecosystem-group: monthly-stack-maintenance
open-pull-requests-limit: 1
rebase-strategy: auto
ignore:
# First-party workspace versions are reconciled after publishing by
# scripts/sync-versions.mjs and the release workflow.
- dependency-name: '@bsv/*'
groups:
bsv-workspace:
# Cross-workspace @bsv/* bumps handled by sync-versions script, not Dependabot
exclude-patterns:
- "@bsv/*"
dev-tooling:
root-security:
applies-to: security-updates
patterns:
- "typescript"
- "ts-standard"
- "jest"
- "ts-jest"
- "@types/*"
ignore:
# Workspace packages managed internally
- dependency-name: "@bsv/sdk"
- dependency-name: "@bsv/wallet-toolbox"
- dependency-name: "@bsv/overlay"
- dependency-name: "@bsv/overlay-express"
- dependency-name: "@bsv/auth-express-middleware"
- dependency-name: "@bsv/payment-express-middleware"
- dependency-name: "@bsv/authsocket"
- dependency-name: "@bsv/authsocket-client"
- dependency-name: "@bsv/message-box-client"
- dependency-name: "@bsv/paymail"
- dependency-name: "@bsv/simple"
- dependency-name: "@bsv/wallet-helper"
- dependency-name: "@bsv/amountinator"
- dependency-name: "@bsv/templates"
- dependency-name: "@bsv/gasp"
- dependency-name: "@bsv/402-pay"
- '*'
exclude-patterns:
- '@bsv/*'

# Infra services each ship their own npm package-lock.json and live OUTSIDE
# the pnpm workspace, so the root entry above does not cover them. List each
# explicitly (incl. the nested notifier). @bsv/* ranges here are rewritten by
# the release workflow, so Dependabot ignores them.
# Infra services live outside the pnpm workspace and maintain package-lock
# files. Dependabot can update them in the same monthly PR; release-time
# version synchronization continues to own their @bsv/* ranges.
- package-ecosystem: npm
directories:
- "/infra/chaintracks-server"
- "/infra/message-box-server"
- "/infra/overlay-server"
- "/infra/uhrp-server-basic"
- "/infra/uhrp-server-cloud-bucket"
- "/infra/uhrp-server-cloud-bucket/notifier"
- "/infra/wab"
- "/infra/wallet-infra"
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 10
- /infra/chaintracks-server
- /infra/message-box-server
- /infra/overlay-server
- /infra/uhrp-server-basic
- /infra/uhrp-server-cloud-bucket
- /infra/uhrp-server-cloud-bucket/notifier
- /infra/wab
- /infra/wallet-infra
patterns:
- '*'
multi-ecosystem-group: monthly-stack-maintenance
open-pull-requests-limit: 1
rebase-strategy: auto
ignore:
- dependency-name: '@bsv/*'
groups:
infra-deps:
infra-security:
applies-to: security-updates
patterns:
- "*"
- '*'
exclude-patterns:
- "@bsv/*"
ignore:
# @bsv/* ranges in infra lockfiles are managed by the release workflow
- dependency-name: "@bsv/*"
- '@bsv/*'

- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
patterns:
- '*'
multi-ecosystem-group: monthly-stack-maintenance
open-pull-requests-limit: 1
rebase-strategy: auto
115 changes: 102 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Reject high and critical dependency advisories
run: pnpm audit:security

- name: Check cross-package version references
# Non-blocking. Multi-package patch PRs (one bump touches several packages whose
# downstream deps can't reference the new versions until publish) will always
Expand Down Expand Up @@ -61,10 +64,20 @@ jobs:
if echo "$CHANGED" | grep -q '^packages/helpers/did/'; then
echo "did=true" >> "$GITHUB_OUTPUT"
fi
if echo "$CHANGED" | grep -q '^packages/wallet/wallet-toolbox/'; then
echo "wallet=true" >> "$GITHUB_OUTPUT"
fi
if echo "$CHANGED" | grep -q '^packages/verifast/'; then
echo "verifast=true" >> "$GITHUB_OUTPUT"
fi
echo "coverage-filter=[${BASE_SHA}]" >> "$GITHUB_OUTPUT"
else
echo "filter=" >> "$GITHUB_OUTPUT"
echo "sdk=true" >> "$GITHUB_OUTPUT"
echo "did=true" >> "$GITHUB_OUTPUT"
echo "wallet=true" >> "$GITHUB_OUTPUT"
echo "verifast=true" >> "$GITHUB_OUTPUT"
echo "coverage-filter=[$(git rev-parse HEAD^)]" >> "$GITHUB_OUTPUT"
fi

- name: Build changed packages
Expand Down Expand Up @@ -118,35 +131,68 @@ jobs:
pnpm --filter @bsv/did run test:coverage
node scripts/normalize-lcov-paths.mjs packages/helpers/did/coverage/lcov.info packages/helpers/did

- name: Generate coverage (wallet-toolbox)
if: steps.scope.outputs.wallet == 'true'
run: |
pnpm --filter @bsv/wallet-toolbox run test:coverage
node scripts/normalize-lcov-paths.mjs packages/wallet/wallet-toolbox/coverage/lcov.info packages/wallet/wallet-toolbox

- name: Generate coverage (VeriFast)
if: steps.scope.outputs.verifast == 'true'
run: |
pnpm --filter @bsv/verifast run test:coverage
node scripts/normalize-lcov-paths.mjs packages/verifast/coverage/lcov.info packages/verifast

- name: Generate coverage for other changed packages
env:
COVERAGE_FILTER: ${{ steps.scope.outputs.coverage-filter }}
run: |
pnpm -r \
--filter "$COVERAGE_FILTER" \
--filter '!@bsv/sdk' \
--filter '!@bsv/did' \
--filter '!@bsv/wallet-toolbox' \
--filter '!@bsv/verifast' \
--filter '!@bsv/ts-stack' \
--if-present run test:coverage

while IFS= read -r report; do
package_dir="${report%/coverage/lcov.info}"
node scripts/normalize-lcov-paths.mjs "$report" "$package_dir"
done < <(find packages -type f -path '*/coverage/lcov.info' | sort)

- name: Compose codecov inputs
id: cov
if: steps.scope.outputs.sdk == 'true' || steps.scope.outputs.did == 'true'
run: |
FILES=""
FLAGS=""
if [ "${{ steps.scope.outputs.sdk }}" = "true" ]; then
FILES="packages/sdk/coverage/lcov.info"
FLAGS="sdk"
fi
if [ "${{ steps.scope.outputs.did }}" = "true" ]; then
FILES="${FILES:+$FILES,}packages/helpers/did/coverage/lcov.info"
FLAGS="${FLAGS:+$FLAGS,}did"
FILES="$(find packages -type f -path '*/coverage/lcov.info' | sort | paste -sd, -)"
if [ -n "$FILES" ]; then
echo "has-coverage=true" >> "$GITHUB_OUTPUT"
else
echo "has-coverage=false" >> "$GITHUB_OUTPUT"
fi
echo "files=$FILES" >> "$GITHUB_OUTPUT"
echo "flags=$FLAGS" >> "$GITHUB_OUTPUT"

- name: Upload coverage to Codecov
if: (steps.scope.outputs.sdk == 'true' || steps.scope.outputs.did == 'true') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
if: steps.cov.outputs.has-coverage == 'true' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ steps.cov.outputs.files }}
flags: ${{ steps.cov.outputs.flags }}
name: ts-stack
slug: bsv-blockchain/ts-stack
# Coverage upload is non-blocking: Codecov CLI GPG-verify/outages must not gate CI.
fail_ci_if_error: false

- name: SonarQube Cloud scan and quality gate
# SONAR_CI_ENABLED is flipped only after a Sonar organization admin
# disables Automatic Analysis; the two methods cannot run together.
# Dependabot changes are covered by audit + dependency review and do
# not receive Actions secrets.
if: vars.SONAR_CI_ENABLED == 'true' && github.actor != 'dependabot[bot]' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

docs-validate:
name: Docs Site Validation
runs-on: ubuntu-latest
Expand Down Expand Up @@ -216,3 +262,46 @@ jobs:
name: conformance-vectors
path: conformance/vectors/
retention-days: 90

dependency-review:
name: Dependency Review
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Block newly introduced high and critical vulnerabilities
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high
comment-summary-in-pr: never

merge-gate:
name: merge-gate
if: always()
needs:
- build-and-test
- docs-validate
- conformance
- dependency-review
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Verify every required CI result
env:
BUILD_RESULT: ${{ needs.build-and-test.result }}
DOCS_RESULT: ${{ needs.docs-validate.result }}
CONFORMANCE_RESULT: ${{ needs.conformance.result }}
DEPENDENCY_RESULT: ${{ needs.dependency-review.result }}
run: |
if [[ "$BUILD_RESULT" != "success" ||
"$DOCS_RESULT" != "success" ||
"$CONFORMANCE_RESULT" != "success" ]]; then
echo "::error::Required CI failed: build=$BUILD_RESULT docs=$DOCS_RESULT conformance=$CONFORMANCE_RESULT"
exit 1
fi
if [[ "$DEPENDENCY_RESULT" != "success" && "$DEPENDENCY_RESULT" != "skipped" ]]; then
echo "::error::Dependency review failed: dependency-review=$DEPENDENCY_RESULT"
exit 1
fi
35 changes: 33 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ on:
required: false
default: ''

concurrency:
group: npm-release
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
environment: npm-production
timeout-minutes: 90
permissions:
contents: write
id-token: write # required for npm OIDC provenance
Expand All @@ -40,8 +46,33 @@ jobs:
registry-url: https://registry.npmjs.org
cache: pnpm

- name: Verify trusted release source
env:
EVENT_NAME: ${{ github.event_name }}
run: |
git fetch origin main
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
echo "::error::Manual npm releases must run from main."
exit 1
fi
elif ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
echo "::error::Release tags must point to a commit reachable from main."
exit 1
fi

- name: Install dependencies
run: pnpm install --frozen-lockfile
# Release builds do not need dependency lifecycle scripts. Package
# prepublish scripts still run explicitly during pnpm publish. Rebuild
# the one audited tool binary used by the workspace build instead of
# allowing arbitrary transitive lifecycle scripts.
run: pnpm install --frozen-lockfile --ignore-scripts

- name: Rebuild the audited build tool
run: pnpm rebuild esbuild

- name: Reject high and critical dependency advisories
run: pnpm audit:security

- name: Build all packages
run: pnpm -r --filter '!@bsv/ts-stack' run build
Expand Down Expand Up @@ -179,7 +210,7 @@ jobs:
git clean -fd

pnpm sync-versions
pnpm install --lockfile-only
pnpm install --lockfile-only --ignore-scripts

# Infra components are NOT in the pnpm workspace — each has its own
# npm package-lock.json that goes stale when sync-versions rewrites
Expand Down
9 changes: 2 additions & 7 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,8 @@ coverage:

patch:
default:
target: 80%
threshold: 1%

flags:
sdk:
paths:
- "packages/sdk/src/"
target: 90%
threshold: 0%

comment:
layout: "reach,diff,flags,files,footer"
Expand Down
Loading
Loading