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
69 changes: 55 additions & 14 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,57 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
time: "04:00"
open-pull-requests-limit: 10
assignees:
- euskadi31
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
assignees:
- euskadi31
# go.work at the root: Dependabot's go.work mode updates every module the
# workspace lists (all modules but tools/*; `make check-modules` fails when
# a module is missing from go.work). One entry per directory would make it
# open the same update once per module.
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
time: "04:00"
cooldown:
default-days: 7
open-pull-requests-limit: 10
groups:
opentelemetry:
patterns:
- "go.opentelemetry.io/*"
assignees:
- euskadi31

# The development tools, one module per tool outside go.work. Each tool is
# an indirect requirement of its module (a `tool` directive), so it is
# allowed by name; the tools' own dependencies follow the tool releases.
- package-ecosystem: gomod
directories:
- "/tools/*"
schedule:
interval: weekly
cooldown:
default-days: 7
allow:
- dependency-name: "github.com/golangci/golangci-lint/v2"
dependency-type: "all"
- dependency-name: "golang.org/x/vuln"
dependency-type: "all"
- dependency-name: "github.com/mattn/goveralls"
dependency-type: "all"
- dependency-name: "github.com/vektra/mockery/v3"
dependency-type: "all"
assignees:
- euskadi31

# The workflows: every action is pinned to a commit SHA with its version in
# a comment, which Dependabot reads to propose the next one.
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
github-actions:
patterns:
- "*"
assignees:
- euskadi31
64 changes: 34 additions & 30 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,59 @@ on:
pull_request:
branches: [master]

# Read-only token for every job: nothing in this workflow writes to the
# repository, its packages or its pull requests.
permissions:
contents: read

# A pull request keeps only its latest run. Every commit pushed to master gets
# its own group, so that a run waiting behind another is never cancelled and
# every master commit keeps a result.
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
build:
name: Build & test (workspace)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@v7
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.work
id: go
cache-dependency-path: "**/go.sum"

- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.12.2
install-only: true
# golangci-lint, govulncheck, goveralls and mockery, each built from its
# pinned module under tools/ and verified by that module's go.sum.
- name: Install the pinned tools
run: make tools

# Mocks are generated, never committed: every test build needs them.
- name: Generate mocks
run: make generate

- name: Workspace sync
run: make sync
- name: Check every module on its own
run: make check-modules

# NOTE: `make generate` is intentionally NOT run in CI yet — the
# .mockery.yaml is being migrated to v3 syntax while the tool pin
# (vektra/mockery v2.53.5) is still v2. Re-enable once the config /
# tool are aligned (tracked in LIMITATIONS.md, slated for Phase 4).
- name: Build all modules
run: make build

- name: Test all modules (race + coverage)
run: make test

# Lint runs in a dedicated step so that gosec/golangci output is easy to
# read. The Makefile iterates over every module with the shared config.
- name: Lint all modules
run: make lint

- name: Upload aggregated coverage to Coveralls
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: build/coverage.out

finish:
needs: build
runs-on: ubuntu-latest
steps:
- name: Coveralls finished
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
# goveralls, built from tools/goveralls, authenticates with the
# read-only workflow token; a Coveralls outage never fails the build.
- name: Upload the coverage to Coveralls
continue-on-error: true
env:
COVERALLS_TOKEN: ${{ github.token }}
run: make coveralls
42 changes: 42 additions & 0 deletions .github/workflows/govulncheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: govulncheck

on:
push:
branches: [master]
pull_request:
branches: [master]
# Weekly, so that an advisory published against the pinned toolchain or a
# dependency surfaces even when nothing changes here.
schedule:
- cron: "17 5 * * 1"
workflow_dispatch:

permissions:
contents: read

# A pull request keeps only its latest run; every other run (master pushes,
# the weekly scan) gets its own group and is never cancelled.
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
govulncheck:
name: govulncheck (every module)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.work
cache-dependency-path: "**/go.sum"

# Every module outside the workspace (its own requirements: what a
# consumer resolves), tests included, with the toolchain go.work pins.
- name: Scan every module
run: make vuln
127 changes: 90 additions & 37 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,64 +1,117 @@
name: Release

# Each module of the workspace is released independently. Go's multi-module
# convention puts the module path in the tag:
# Each module of the workspace is released on its own (docs/releasing.md).
# The module path is part of the tag:
#
# v1.2.3 -> the root module (github.com/hyperscale-stack/security)
# http/v1.2.3 -> the github.com/hyperscale-stack/security/http module
# oauth2/v1.2.3 -> the github.com/hyperscale-stack/security/oauth2 module
# v1.2.3 -> the core module (github.com/hyperscale-stack/security)
# http/v1.2.3 -> github.com/hyperscale-stack/security/http
# oauth2/store/sql/v1.2.3 -> github.com/hyperscale-stack/security/oauth2/store/sql
#
# Pushing such a tag validates the tagged state and publishes a GitHub
# release. Nothing is force-pushed and no tag is created by this workflow.
# Pushing such a tag verifies the tagged commit with a read-only token, then a
# separate job publishes the GitHub release. Nothing is pushed and no tag is
# created by this workflow. scripts/release-check.sh refuses any tag the
# filters below let through that is not a release of a module.
on:
push:
tags:
- "v*"
- "*/v*"
- "v[0-9]*"
- "**/v[0-9]*"

permissions:
contents: write
contents: read

# One run per tag, never cancelled halfway through a release.
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
name: Release ${{ github.ref_name }}
verify:
name: Verify ${{ github.ref_name }}
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
dir: ${{ steps.tag.outputs.dir }}
previous: ${{ steps.tag.outputs.previous }}
prerelease: ${{ steps.tag.outputs.prerelease }}
steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The tags and origin/master: release-check verifies that the
# tagged commit is on master and finds the module's previous tag.
fetch-depth: 0
persist-credentials: false

- name: Set up Go
uses: actions/setup-go@v7
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.x"
check-latest: true
go-version-file: go.work
# A release never reads a cache that another run wrote.
cache: false

- name: Resolve the released module
id: mod
run: |
tag='${{ github.ref_name }}'
case "$tag" in
*/v*) echo "dir=${tag%/v*}" >> "$GITHUB_OUTPUT" ;;
*) echo "dir=." >> "$GITHUB_OUTPUT" ;;
esac
- name: Install the pinned tools
run: make tools

- name: Generate mocks
run: make generate

# Tag, module and version; placeholder requirements; commit on master;
# the module built and vetted the way a consumer resolves it.
- name: Check the tag
id: tag
env:
TAG: ${{ github.ref_name }}
run: ./scripts/release-check.sh "$TAG"

- name: Workspace sync
run: make sync
- name: Check every module on its own
run: make check-modules

# The whole workspace is built and tested so a tag can never publish a
# module whose dependencies (sibling modules) are in a broken state.
- name: Build all modules
run: make build

- name: Test all modules (race + coverage)
run: make test

- name: Publish GitHub release
uses: softprops/action-gh-release@v3
with:
name: ${{ github.ref_name }}
generate_release_notes: true
body: |
Release of the `${{ steps.mod.outputs.dir }}` module.
- name: Lint all modules
run: make lint

# The released module's own code, outside the workspace: an advisory
# in another module or only reachable from tests does not block this
# release. The full scan (every module, tests included) is the
# govulncheck workflow, green on the release commit (docs/releasing.md).
- name: Scan the released module (govulncheck)
env:
DIR: ${{ steps.tag.outputs.dir }}
run: cd "$DIR" && GOWORK=off "$GITHUB_WORKSPACE/build/bin/govulncheck" ./...

See [CHANGELOG.md](https://github.com/hyperscale-stack/security/blob/master/CHANGELOG.md)
for the consolidated history.
publish:
name: Publish ${{ github.ref_name }}
needs: verify
runs-on: ubuntu-latest
# Required reviewers can be set on this environment to approve each
# publication before the write token below is minted.
environment: release
permissions:
contents: write # create the GitHub release; no checkout, no third-party code
steps:
- name: Create the GitHub release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
DIR: ${{ needs.verify.outputs.dir }}
PREVIOUS: ${{ needs.verify.outputs.previous }}
PRERELEASE: ${{ needs.verify.outputs.prerelease }}
run: |
module="github.com/$GITHUB_REPOSITORY"
if [ "$DIR" != "." ]; then module="$module/$DIR"; fi
set -- --repo "$GITHUB_REPOSITORY" --verify-tag --title "$TAG" --generate-notes \
--notes "Release of the \`$module\` module. See [CHANGELOG.md](https://github.com/$GITHUB_REPOSITORY/blob/master/CHANGELOG.md) for the consolidated history."
# Notes since the previous release of the same module, not of any
# module of the repository.
if [ -n "$PREVIOUS" ]; then set -- "$@" --notes-start-tag "$PREVIOUS"; fi
if [ "$PRERELEASE" = "true" ]; then set -- "$@" --prerelease; fi
# The repository's "latest" release (README badge) is the core's.
if [ "$DIR" != "." ]; then set -- "$@" --latest=false; fi
gh release create "$TAG" "$@"
15 changes: 13 additions & 2 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# mockery v3, pinned in tools/mockery and run by `make generate` (CI runs it
# before build, test and lint). Mocks are in-package mock_<interface>_test.go
# files: they exist only in test binaries, never in a library build, and are
# never committed (.gitignore: mock_*). Every module whose packages get mocks
# keeps a mockery_test.go importing testify/mock, so its go.mod and go.sum are
# the same with or without them.
# Unexported interfaces included: their in-package mocks serve in-package tests.
all: true
dir: '{{.InterfaceDir}}'
filename: 'mock_{{.InterfaceName | snakecase}}.go'
structname: Mock{{.InterfaceName}}
filename: 'mock_{{.InterfaceName | snakecase}}_test.go'
structname: 'Mock{{.InterfaceName}}'
pkgname: '{{.SrcPackageName}}'
inpackage: true
template: testify
Expand All @@ -11,3 +18,7 @@ packages:
github.com/hyperscale-stack/security:
config:
recursive: true
# Library packages only: the examples and the private test modules need
# no mocks, and the tool modules are not part of the workspace.
exclude-subpkg-regex:
- '^github\.com/hyperscale-stack/security/(examples|internal|tools)(/|$)'
Loading
Loading