Compare commits

...
19 Commits
Author SHA1 Message Date
argoyle db1ff0e7f6 Merge pull request 'chore(release): prepare for v0.1.1' (#21) from next-release into main
auth / coverage-baseline (push) Successful in 58s
Unbound Release / Check Preconditions (push) Successful in 26s
Unbound Release / Create Tag (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 29s
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
Unbound Release / Create Release (push) Successful in 29s
Release / release (push) Successful in 2m52s
pre-commit / pre-commit (push) Successful in 3m52s
Reviewed-on: #21
2026-08-29 11:28:31 +00:00
releaser 4f9539c526 chore(release): prepare for v0.1.1
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
auth / test (pull_request) Successful in 56s
auth / coverage-baseline (pull_request) Skipped
auth / vulnerabilities (pull_request) Successful in 44s
pre-commit / pre-commit (pull_request) Successful in 3m54s
2026-08-21 08:07:15 +00:00
releaser 65a1814405 chore(release): prepare for v0.1.1
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
2026-08-21 08:07:11 +00:00
renovate d25ee3cd23 fix(deps): update module github.com/stretchr/testify to v1.12.1 (#18)
auth / coverage-baseline (push) Successful in 50s
Unbound Release / Check Preconditions (push) Successful in 22s
Unbound Release / Create Tag (push) Skipped
auth / test (push) Skipped
Unbound Release / Create Release (push) Successful in 24s
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 38s
Release / release (push) Successful in 2m48s
2026-08-21 08:01:42 +00:00
renovate e51d828a61 chore(deps): update pre-commit hook golangci/golangci-lint to v2.13.1 (#19)
Unbound Release / Create Tag (push) Skipped
auth / coverage-baseline (push) Successful in 1m3s
Unbound Release / Check Preconditions (push) Successful in 22s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 35s
Release / release (push) Successful in 2m46s
pre-commit / pre-commit (push) Successful in 3m58s
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
Unbound Release / Create Release (push) Successful in 24s
2026-08-21 07:06:02 +00:00
renovate 2dbf17b2ea fix(deps): update module github.com/stretchr/testify to v1.12.0 (#16)
auth / coverage-baseline (push) Successful in 48s
Unbound Release / Create Tag (push) Skipped
Unbound Release / Check Preconditions (push) Successful in 21s
Release / release (push) Successful in 45m53s
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
Unbound Release / Generate Changelog and Handle PR (push) Successful in 42s
Unbound Release / Create Release (push) Successful in 24s
2026-08-17 09:07:43 +00:00
argoyle 37757be1fc Merge pull request 'chore(deps): update actions/setup-python action to v7' (#14) from renovate/actions-setup-python-7.x into main
Unbound Release / Create Tag (push) Skipped
auth / coverage-baseline (push) Successful in 1m2s
Unbound Release / Check Preconditions (push) Successful in 26s
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
Release / release (push) Successful in 18m39s
Unbound Release / Create Release (push) Successful in 26s
Unbound Release / Generate Changelog and Handle PR (push) Successful in 49s
Reviewed-on: #14
2026-07-25 11:38:30 +00:00
renovate 1247904548 chore(deps): update actions/setup-python action to v7
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
renovate/stability-days Updates have met minimum release age requirement
auth / coverage-baseline (pull_request) Skipped
auth / test (pull_request) Successful in 1m8s
pre-commit / pre-commit (pull_request) Successful in 2m29s
auth / vulnerabilities (pull_request) Successful in 47s
2026-07-23 04:01:06 +00:00
argoyle c119182df2 Merge pull request 'chore(deps): update actions/setup-go action to v7' (#12) from renovate/actions-setup-go-7.x into main
auth / coverage-baseline (push) Successful in 1m7s
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
Release / release (push) Successful in 1m6s
pre-commit / pre-commit (push) Successful in 2m55s
Reviewed-on: #12
2026-07-19 18:55:56 +00:00
renovate 92df99e392 chore(deps): update actions/setup-go action to v7
renovate/stability-days Updates have met minimum release age requirement
auth / test (pull_request) Successful in 1m6s
auth / coverage-baseline (pull_request) Has been skipped
auth / vulnerabilities (pull_request) Successful in 44s
pre-commit / pre-commit (pull_request) Successful in 2m5s
2026-07-19 03:01:13 +00:00
renovate 6c451d0db7 chore(deps): update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.26.0 (#10)
auth / test (push) Has been skipped
auth / vulnerabilities (push) Has been skipped
Release / release (push) Successful in 49s
auth / coverage-baseline (push) Successful in 1m36s
pre-commit / pre-commit (push) Successful in 3m42s
2026-06-27 22:08:06 +00:00
argoyle bb0a74b6a1 Merge pull request 'chore(deps): update actions/cache action to v6' (#8) from renovate/actions-cache-6.x into main
auth / test (push) Has been skipped
auth / coverage-baseline (push) Successful in 1m47s
auth / vulnerabilities (push) Has been skipped
Release / release (push) Successful in 1m1s
pre-commit / pre-commit (push) Successful in 3m39s
Reviewed-on: #8
2026-06-26 15:56:51 +00:00
renovate f1e78d3b40 chore(deps): update actions/cache action to v6
renovate/stability-days Updates have met minimum release age requirement
auth / coverage-baseline (pull_request) Has been skipped
auth / vulnerabilities (pull_request) Successful in 58s
pre-commit / pre-commit (pull_request) Successful in 3m41s
auth / test (pull_request) Successful in 6m28s
2026-06-26 15:01:16 +00:00
argoyle a38da7e7f4 Merge pull request 'chore(deps): update actions/checkout action to v7' (#6) from renovate/actions-checkout-7.x into main
auth / test (push) Has been skipped
auth / vulnerabilities (push) Has been skipped
auth / coverage-baseline (push) Successful in 2m38s
pre-commit / pre-commit (push) Successful in 5m27s
Release / release (push) Successful in 1m8s
Reviewed-on: #6
2026-06-20 18:38:50 +00:00
renovate 0074e7a74c chore(deps): update actions/checkout action to v7
renovate/stability-days Updates have met minimum release age requirement
auth / coverage-baseline (pull_request) Has been skipped
auth / vulnerabilities (pull_request) Successful in 1m23s
auth / test (pull_request) Successful in 3m11s
pre-commit / pre-commit (pull_request) Successful in 5m15s
2026-06-20 18:01:23 +00:00
argoyle 1fd859af5c chore(ci): add shared-lib scaffolding and functional coverage gate (#4)
auth / test (push) Has been skipped
auth / vulnerabilities (push) Has been skipped
Release / release (push) Successful in 1m16s
auth / coverage-baseline (push) Successful in 2m53s
pre-commit / pre-commit (push) Successful in 5m34s
2026-06-15 17:53:44 +00:00
renovate 679fd59cbc fix(deps): update module github.com/stretchr/testify to v1.11.1 (#2)
auth / test (push) Has been skipped
auth / vulnerabilities (push) Has been skipped
2026-06-15 13:19:50 +00:00
argoyle e322445b82 Merge pull request 'chore: Configure Renovate' (#1) from renovate/configure into main
auth / vulnerabilities (push) Has been skipped
auth / test (push) Has been skipped
Reviewed-on: #1
2026-06-15 12:09:44 +00:00
renovate c02a86f0aa Add renovate.json
auth / test (pull_request) Successful in 1m30s
auth / vulnerabilities (pull_request) Successful in 1m49s
2026-06-15 10:01:11 +00:00
15 changed files with 379 additions and 21 deletions
+11
View File
@@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true
[*.go]
indent_style = tab
indent_size = 2
+77 -5
View File
@@ -11,8 +11,8 @@ jobs:
if: gitea.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: 'stable'
- name: Format check
@@ -20,13 +20,85 @@ jobs:
go install mvdan.cc/gofumpt@latest
test -z "$(gofumpt -l .)"
- name: Run tests
run: go test -race ./...
run: go test -race -coverprofile=coverage.txt ./...
- name: Filter test files from coverage
run: |
grep -v -E '_test\.go:' coverage.txt > coverage.filtered.txt || true
mv coverage.filtered.txt coverage.txt
- name: Check coverage
id: coverage
run: |
go install github.com/vladopajic/go-test-coverage/v2@latest
go-test-coverage --config ./.testcoverage.yml --github-action-output
- name: Restore baseline coverage
uses: actions/cache/restore@v6
with:
path: coverage-baseline.txt
key: coverage-baseline-${{ gitea.run_id }}
restore-keys: |
coverage-baseline-
- name: Compare coverage
run: |
CURRENT="${{ steps.coverage.outputs.total-coverage }}"
if [ -f coverage-baseline.txt ]; then
BASE=$(cat coverage-baseline.txt)
echo "Base coverage: ${BASE}%"
echo "Current coverage: ${CURRENT}%"
if [ "$(echo "$CURRENT < $BASE" | bc -l)" -eq 1 ]; then
echo "::error::Coverage decreased from ${BASE}% to ${CURRENT}%"
exit 1
fi
echo "Coverage maintained or improved: ${BASE}% -> ${CURRENT}%"
else
echo "No baseline coverage found yet, skipping comparison"
echo "Current coverage: ${CURRENT}%"
fi
- name: Post coverage comment
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_URL: ${{ gitea.server_url }}
run: |
COVERAGE="${{ steps.coverage.outputs.total-coverage }}"
curl -X POST "${GITEA_URL}/api/v1/repos/${{ gitea.repository }}/issues/${{ gitea.event.pull_request.number }}/comments" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"body\": \"## Coverage Report\n\nTotal coverage: **${COVERAGE}%**\"}"
coverage-baseline:
# Records main's coverage into the Actions cache for the next PR's
# regression gate to read. Post-merge only, not a required check, blocks
# nothing (cf. ADR-0010).
if: gitea.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: 'stable'
- name: Compute coverage
id: coverage
run: |
go install github.com/vladopajic/go-test-coverage/v2@latest
go test -coverprofile=coverage.txt ./...
grep -v -E '_test\.go:' coverage.txt > coverage.filtered.txt || true
mv coverage.filtered.txt coverage.txt
go-test-coverage --config ./.testcoverage.yml --github-action-output
- name: Write baseline file
run: echo "${{ steps.coverage.outputs.total-coverage }}" > coverage-baseline.txt
- name: Save baseline to cache
uses: actions/cache/save@v6
with:
path: coverage-baseline.txt
key: coverage-baseline-${{ gitea.run_id }}
vulnerabilities:
if: gitea.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: 'stable'
- name: Check vulnerabilities
+25
View File
@@ -0,0 +1,25 @@
name: pre-commit
permissions: read-all
on:
pull_request:
push:
branches:
- main
jobs:
pre-commit:
runs-on: ubuntu-latest
env:
SKIP: no-commit-to-branch
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version: stable
- uses: actions/setup-python@v7
with:
python-version: '3.14'
- name: Install goimports
run: go install golang.org/x/tools/cmd/goimports@latest
- uses: pre-commit/action@v3.0.1
+9
View File
@@ -0,0 +1,9 @@
name: Release
on:
push:
branches: [main]
jobs:
release:
uses: unboundsoftware/shared-workflows/.gitea/workflows/Release.yml@main
+1
View File
@@ -2,3 +2,4 @@
.claude
/release
coverage.txt
coverage-baseline.txt
+22
View File
@@ -0,0 +1,22 @@
version: "2"
run:
allow-parallel-runners: true
linters:
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
formatters:
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+39
View File
@@ -0,0 +1,39 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
args:
- --allow-multiple-documents
- id: check-added-large-files
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.26.0
hooks:
- id: commitlint
stages: [ commit-msg ]
additional_dependencies: [ '@commitlint/config-conventional' ]
- repo: https://github.com/dnephin/pre-commit-golang
rev: v0.5.1
hooks:
- id: go-mod-tidy
- id: go-imports
args:
- -local
- gitea.unbound.se/shiny/auth
- repo: https://github.com/lietu/go-pre-commit
rev: v1.0.0
hooks:
- id: go-test
- id: gofumpt
- repo: https://github.com/golangci/golangci-lint
rev: v2.13.1
hooks:
- id: golangci-lint-full
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
+13
View File
@@ -0,0 +1,13 @@
# Coverage configuration for go-test-coverage
# https://github.com/vladopajic/go-test-coverage
profile: coverage.txt
threshold:
file: 0
package: 0
total: 0
exclude:
paths:
- _test\.go$
+3
View File
@@ -0,0 +1,3 @@
{
"version": "v0.1.1"
}
+29
View File
@@ -0,0 +1,29 @@
# Changelog
All notable changes to this project will be documented in this file.
## [0.1.1] - 2026-08-21
### 🐛 Bug Fixes
- *(deps)* Update module github.com/stretchr/testify to v1.11.1 (#2)
- *(deps)* Update module github.com/stretchr/testify to v1.12.0 (#16)
- *(deps)* Update module github.com/stretchr/testify to v1.12.1 (#18)
### ⚙️ Miscellaneous Tasks
- *(ci)* Add shared-lib scaffolding and functional coverage gate (#4)
- *(deps)* Update actions/checkout action to v7
- *(deps)* Update actions/cache action to v6
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.26.0 (#10)
- *(deps)* Update actions/setup-go action to v7
- *(deps)* Update actions/setup-python action to v7
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.13.1 (#19)
## [0.1.0] - 2026-06-15
### 🚀 Features
- Initial shared auth module
<!-- generated by git-cliff -->
+58
View File
@@ -0,0 +1,58 @@
# auth
Shared Go library with authentication primitives for all Shiny backend services.
## Shared Documentation
@../docs/claude/architecture.md
@../docs/claude/go-services.md
@../docs/claude/conventions.md
## Library Information
### Purpose
Single home for the `user`-header auth and secret-startup-guard code that was
previously byte-identical-copied into every backend (the `auth` package and
`cmd/service/secrets_guard.go`). Enforces ADR-0005 (HMAC-signed `user` header,
keyless fail-open only in acctest) and ADR-0006 (fail closed when required
secrets are missing in `staging`/`production`).
### Usage
```go
import "gitea.unbound.se/shiny/auth"
// Fail closed on missing deployed secrets before serving (ADR-0005/0006).
if missing := auth.MissingDeployedSecrets(environment, map[string]string{
"USER_SIGNING_KEY": cfg.UserSigningKey,
"INTERNAL_API_KEY": cfg.InternalAPIKey,
}); len(missing) > 0 {
log.Fatalf("refusing to start: missing secrets in %s: %v", environment, missing)
}
// Verify the gateway's signed user header and inject *User into the context.
handler = auth.UserMiddleware([]byte(cfg.UserSigningKey))(handler)
// Read the authenticated user downstream.
user := auth.FromContext(ctx)
if user.HasRole("admin") { /* ... */ }
```
### Exported API
- `UserMiddleware(signingKey []byte)` — HTTP middleware verifying the
HMAC-signed `user` header; injects `*User` into the request context.
- `FromContext(ctx) *User`, `User.HasRole(...) bool`, `ContextKey`/`UserKey`.
- `MissingDeployedSecrets(environment string, secrets map[string]string) []string`
— returns the sorted names of secrets that are empty in `staging`/`production`
(nil for any other environment, e.g. `development`/acctest).
### Conventions
Standard Shiny library scaffolding: `gofumpt`/`goimports -local`, golangci-lint,
gitleaks and conventional-commit checks via pre-commit; coverage-regression gate
in CI (`.testcoverage.yml`); releases auto-tagged from conventional commits by
the shared Release workflow. Bump the consuming services' `go.mod` after a
release. A breaking change to the signed-header or secret-guard contract is a
cross-service change — see ADR-0005/0006 before changing it.
+80
View File
@@ -0,0 +1,80 @@
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
#
# Lines starting with "#" are comments.
# Configuration options are organized into tables and keys.
# See documentation for more information on available options.
[changelog]
# template for the changelog header
header = """
# Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{% if commit.breaking %}[**breaking**] {% endif %}\
{{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
# template for the changelog footer
footer = """
<!-- generated by git-cliff -->
"""
# remove the leading and trailing s
trim = true
# postprocessors
postprocessors = [
# { pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL
]
# render body even when there are no releases to process
# render_always = true
# output file path
# output = "test.md"
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# process each line of a commit as an individual commit
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
# Replace issue numbers
#{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"},
# Check spelling of the commit with https://github.com/crate-ci/typos
# If the spelling is incorrect, it will be automatically fixed.
#{ pattern = '.*', replace_command = 'typos --write-changes -' },
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
]
# filter out the commits that are not matched by commit parsers
filter_commits = false
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
+2 -6
View File
@@ -2,10 +2,6 @@ module gitea.unbound.se/shiny/auth
go 1.25
require github.com/stretchr/testify v1.10.0
require github.com/stretchr/testify v1.12.1
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require go.yaml.in/yaml/v3 v3.0.5 // indirect
+4 -10
View File
@@ -1,10 +1,4 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}