22 Commits

Author SHA1 Message Date
renovate 775d25cb59 chore(deps): update dependency go to v1.26.2 (#300)
Release / release (push) Successful in 1m0s
authz_client / vulnerabilities (push) Successful in 1m46s
authz_client / test (push) Successful in 2m10s
pre-commit / pre-commit (push) Successful in 6m1s
2026-04-10 00:13:25 +00:00
renovate ef992cb9db chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.4 (#298)
Release / release (push) Successful in 1m6s
authz_client / vulnerabilities (push) Successful in 1m38s
authz_client / test (push) Successful in 2m18s
pre-commit / pre-commit (push) Successful in 6m1s
2026-03-22 18:11:14 +00:00
renovate c3b8a3f1ce chore(deps): update pre-commit hook gitleaks/gitleaks to v8.30.1 (#296)
Release / release (push) Successful in 1m29s
authz_client / vulnerabilities (push) Successful in 2m10s
authz_client / test (push) Successful in 3m0s
pre-commit / pre-commit (push) Successful in 7m11s
2026-03-12 16:09:43 +00:00
releaser 45512115c5 chore(release): prepare for v0.5.0 (#295)
Release / release (push) Successful in 40s
authz_client / vulnerabilities (push) Successful in 1m23s
authz_client / test (push) Successful in 2m1s
pre-commit / pre-commit (push) Successful in 4m10s
## [0.5.0] - 2026-03-12

### 🚀 Features

- *(client)* Add API key authentication for /authz endpoint (#294)

### ⚙️ Miscellaneous Tasks

- *(deps)* Update golang:1.25.5 docker digest to 3a01526 (#271)
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.24.0 (#273)
- *(deps)* Update dependency go to v1.25.6 (#274)
- *(deps)* Update golang docker tag to v1.25.6 (#275)
- Remove GitLab CI configuration
- Add code coverage integration
- *(deps)* Update dependency go to v1.25.7 (#279)
- *(deps)* Update dependency go to v1.26.0 (#280)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.9.0 (#281)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.10.0 (#282)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.10.1 (#283)
- *(deps)* Update dependency go to v1.26.1 (#286)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.1 (#288)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.2 (#290)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.3 (#292)

<!-- generated by git-cliff -->

---

**Note:** Please use **Squash Merge** when merging this PR.

Reviewed-on: #295
Co-authored-by: Unbound Releaser <releaser@unbound.se>
Co-committed-by: Unbound Releaser <releaser@unbound.se>
2026-03-12 07:39:47 +00:00
argoyle fe0abd62c8 feat(client): add API key authentication for /authz endpoint (#294)
Release / release (push) Successful in 1m15s
authz_client / vulnerabilities (push) Successful in 2m9s
authz_client / test (push) Successful in 2m21s
pre-commit / pre-commit (push) Successful in 4m46s
## Summary

- Add `WithAPIKey(key string)` option to `PrivilegeHandler`
- When set, `Fetch()` sends `Authorization: Bearer <key>` header
- Backward compatible: no key = no header (existing behavior)

## Test plan

- [x] Unit test verifying Authorization header is sent
- [x] Unit test verifying no header without key
- [x] Existing tests still pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #294
2026-03-12 07:32:12 +00:00
renovate a54cf45a4b chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.3 (#292)
Release / release (push) Successful in 1m21s
authz_client / vulnerabilities (push) Successful in 2m9s
authz_client / test (push) Successful in 4m40s
pre-commit / pre-commit (push) Successful in 7m39s
2026-03-10 11:12:34 +00:00
renovate f9a5ef7085 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.2 (#290)
pre-commit / pre-commit (push) Successful in 4m44s
Release / release (push) Successful in 1m2s
authz_client / vulnerabilities (push) Failing after 2h42m46s
authz_client / test (push) Failing after 2h42m53s
2026-03-07 22:09:47 +00:00
renovate 200e7cf963 chore(deps): update pre-commit hook golangci/golangci-lint to v2.11.1 (#288)
Release / release (push) Successful in 57s
authz_client / vulnerabilities (push) Successful in 1m46s
authz_client / test (push) Successful in 2m49s
pre-commit / pre-commit (push) Successful in 5m49s
2026-03-06 15:11:17 +00:00
renovate 110f6206f9 chore(deps): update dependency go to v1.26.1 (#286)
Release / release (push) Successful in 1m13s
authz_client / vulnerabilities (push) Successful in 1m36s
authz_client / test (push) Successful in 2m27s
pre-commit / pre-commit (push) Successful in 10m39s
2026-03-06 01:18:10 +00:00
renovate c53d80792c chore(deps): update pre-commit hook golangci/golangci-lint to v2.10.1 (#283)
Release / release (push) Successful in 1m31s
authz_client / vulnerabilities (push) Successful in 2m39s
authz_client / test (push) Successful in 3m54s
pre-commit / pre-commit (push) Successful in 8m34s
2026-02-17 17:01:30 +00:00
renovate ebc0c3bb8e chore(deps): update pre-commit hook golangci/golangci-lint to v2.10.0 (#282)
Release / release (push) Failing after 41s
authz_client / vulnerabilities (push) Successful in 17m19s
authz_client / test (push) Successful in 18m59s
pre-commit / pre-commit (push) Successful in 52m24s
2026-02-17 15:01:11 +00:00
renovate cb59762fc9 chore(deps): update pre-commit hook golangci/golangci-lint to v2.9.0 (#281)
authz_client / vulnerabilities (push) Successful in 2m12s
Release / release (push) Successful in 1m55s
authz_client / test (push) Successful in 4m10s
pre-commit / pre-commit (push) Successful in 17m58s
2026-02-11 07:13:35 +00:00
renovate a82466cb27 chore(deps): update dependency go to v1.26.0 (#280)
Release / release (push) Successful in 1m22s
authz_client / vulnerabilities (push) Successful in 4m20s
authz_client / test (push) Successful in 4m30s
pre-commit / pre-commit (push) Successful in 9m2s
2026-02-11 06:19:26 +00:00
renovate 29eab978f7 chore(deps): update dependency go to v1.25.7 (#279)
Release / release (push) Failing after 58s
authz_client / test (push) Successful in 4m30s
authz_client / vulnerabilities (push) Successful in 3m54s
pre-commit / pre-commit (push) Successful in 12m54s
2026-02-04 16:16:32 +00:00
argoyle f3166426b6 Merge pull request 'ci: add code coverage integration' (#277) from ci-coverage-integration into main
Release / release (push) Failing after 4m57s
authz_client / vulnerabilities (push) Successful in 7m21s
authz_client / test (push) Successful in 8m12s
pre-commit / pre-commit (push) Successful in 14m37s
Reviewed-on: #277
2026-01-28 12:38:20 +00:00
argoyle 3171c53393 ci: add code coverage integration
authz_client / test (pull_request) Successful in 6m57s
authz_client / vulnerabilities (pull_request) Successful in 7m26s
pre-commit / pre-commit (pull_request) Successful in 12m3s
Add go-test-coverage for coverage threshold enforcement. Coverage data
is uploaded as artifacts on main branch and compared against baseline
in PRs using shell script that gracefully handles first run without
baseline. PR comments show coverage percentage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 13:03:07 +01:00
argoyle 7af8e00b4c Merge pull request 'chore: remove GitLab CI configuration' (#276) from remove-gitlab-ci into main
Release / release (push) Failing after 1m59s
authz_client / test (push) Successful in 2m49s
pre-commit / pre-commit (push) Successful in 7m12s
authz_client / vulnerabilities (push) Successful in 10m29s
Reviewed-on: #276
2026-01-18 20:15:35 +00:00
argoyle 0c0f321b33 chore: remove GitLab CI configuration
authz_client / test (pull_request) Successful in 6m42s
authz_client / vulnerabilities (pull_request) Successful in 9m50s
pre-commit / pre-commit (pull_request) Successful in 18m32s
2026-01-18 20:36:13 +01:00
renovate 87805f1552 chore(deps): update golang docker tag to v1.25.6 (#275)
authz_client / vulnerabilities (push) Successful in 1m28s
authz_client / test (push) Successful in 2m27s
Release / release (push) Successful in 2m49s
pre-commit / pre-commit (push) Successful in 5m23s
2026-01-15 22:06:58 +00:00
renovate 74ee30bccc chore(deps): update dependency go to v1.25.6 (#274)
Release / release (push) Successful in 2m33s
authz_client / test (push) Successful in 4m27s
authz_client / vulnerabilities (push) Successful in 6m55s
pre-commit / pre-commit (push) Successful in 15m1s
2026-01-15 20:06:38 +00:00
renovate 646e4f31c4 chore(deps): update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.24.0 (#273)
Release / release (push) Successful in 2m12s
authz_client / test (push) Successful in 5m48s
authz_client / vulnerabilities (push) Successful in 6m17s
pre-commit / pre-commit (push) Successful in 17m3s
2026-01-13 21:08:37 +00:00
renovate 881fac379f chore(deps): update golang:1.25.5 docker digest to 3a01526 (#271)
authz_client / test (push) Successful in 2m23s
authz_client / vulnerabilities (push) Successful in 2m32s
Release / release (push) Successful in 1m57s
pre-commit / pre-commit (push) Successful in 6m25s
2026-01-13 14:35:12 +00:00
9 changed files with 151 additions and 52 deletions
+55
View File
@@ -17,6 +17,61 @@ jobs:
- name: Run tests - name: Run tests
run: go test -race -coverprofile=coverage.txt ./... run: go test -race -coverprofile=coverage.txt ./...
- name: Check coverage
uses: vladopajic/go-test-coverage@v2
with:
config: ./.testcoverage.yml
# Download baseline coverage from main branch (for PRs)
- name: Download baseline coverage
if: gitea.event_name == 'pull_request'
uses: actions/download-artifact@v3
with:
name: coverage-baseline
path: ./baseline
continue-on-error: true
# Compare coverage against baseline (for PRs)
- name: Compare coverage
if: gitea.event_name == 'pull_request'
run: |
CURRENT=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%')
if [ -f ./baseline/coverage.txt ]; then
BASE=$(go tool cover -func=./baseline/coverage.txt | grep "^total:" | awk '{print $NF}' | tr -d '%')
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, skipping comparison"
echo "Current coverage: ${CURRENT}%"
fi
# Upload coverage as baseline (only on main)
- name: Upload coverage baseline
if: gitea.ref == 'refs/heads/main'
uses: actions/upload-artifact@v3
with:
name: coverage-baseline
path: coverage.txt
retention-days: 90
# Post coverage to PR comment
- name: Post coverage comment
if: gitea.event_name == 'pull_request'
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_URL: ${{ gitea.server_url }}
run: |
COVERAGE=$(go tool cover -func=coverage.txt | grep "^total:" | awk '{print $NF}')
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}**\"}"
vulnerabilities: vulnerabilities:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
-38
View File
@@ -1,38 +0,0 @@
include:
- template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
- project: unboundsoftware/ci-templates
file: Defaults.gitlab-ci.yml
- project: unboundsoftware/ci-templates
file: Release.gitlab-ci.yml
- project: unboundsoftware/ci-templates
file: Pre-Commit-Go.gitlab-ci.yml
image: amd64/golang:1.25.5@sha256:ad03ba93327b8a6143b49373790b5d92c28067bdb814418509466122ee9c9e63
stages:
- deps
- test
deps:
stage: deps
script:
- go mod download
test:
stage: test
dependencies:
- deps
script:
- CGO_ENABLED=1 go test -mod=readonly -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=$(go list ./... | tr '\n' , | sed 's/,$//') ./...
- go tool cover -html=coverage.txt -o coverage.html
- go tool cover -func=coverage.txt
- curl -Os https://uploader.codecov.io/latest/linux/codecov
- chmod +x codecov
- ./codecov -t ${CODECOV_TOKEN} -R $CI_PROJECT_DIR -C $CI_COMMIT_SHA -r $CI_PROJECT_PATH
vulnerabilities:
stage: test
image: amd64/golang:1.25.5@sha256:ad03ba93327b8a6143b49373790b5d92c28067bdb814418509466122ee9c9e63
script:
- go install golang.org/x/vuln/cmd/govulncheck@latest
- govulncheck ./...
+3 -3
View File
@@ -11,7 +11,7 @@ repos:
- --allow-multiple-documents - --allow-multiple-documents
- id: check-added-large-files - id: check-added-large-files
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
rev: v9.23.0 rev: v9.24.0
hooks: hooks:
- id: commitlint - id: commitlint
stages: [ commit-msg ] stages: [ commit-msg ]
@@ -30,10 +30,10 @@ repos:
- id: go-test - id: go-test
- id: gofumpt - id: gofumpt
- repo: https://github.com/golangci/golangci-lint - repo: https://github.com/golangci/golangci-lint
rev: v2.8.0 rev: v2.11.4
hooks: hooks:
- id: golangci-lint-full - id: golangci-lint-full
- repo: https://github.com/gitleaks/gitleaks - repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0 rev: v8.30.1
hooks: hooks:
- id: gitleaks - 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$
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"version": "v0.4.1" "version": "v0.5.0"
} }
+24
View File
@@ -2,6 +2,30 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [0.5.0] - 2026-03-12
### 🚀 Features
- *(client)* Add API key authentication for /authz endpoint (#294)
### ⚙️ Miscellaneous Tasks
- *(deps)* Update golang:1.25.5 docker digest to 3a01526 (#271)
- *(deps)* Update pre-commit hook alessandrojcm/commitlint-pre-commit-hook to v9.24.0 (#273)
- *(deps)* Update dependency go to v1.25.6 (#274)
- *(deps)* Update golang docker tag to v1.25.6 (#275)
- Remove GitLab CI configuration
- Add code coverage integration
- *(deps)* Update dependency go to v1.25.7 (#279)
- *(deps)* Update dependency go to v1.26.0 (#280)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.9.0 (#281)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.10.0 (#282)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.10.1 (#283)
- *(deps)* Update dependency go to v1.26.1 (#286)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.1 (#288)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.2 (#290)
- *(deps)* Update pre-commit hook golangci/golangci-lint to v2.11.3 (#292)
## [0.4.1] - 2026-01-09 ## [0.4.1] - 2026-01-09
### ⚙️ Miscellaneous Tasks ### ⚙️ Miscellaneous Tasks
+21 -9
View File
@@ -28,6 +28,7 @@ type PrivilegeHandler struct {
*sync.RWMutex *sync.RWMutex
client *http.Client client *http.Client
baseURL string baseURL string
apiKey string
privileges map[string]map[string]*CompanyPrivileges privileges map[string]map[string]*CompanyPrivileges
} }
@@ -41,6 +42,13 @@ func WithBaseURL(url string) OptsFunc {
} }
} }
// WithAPIKey sets an API key used as a Bearer token when fetching privileges
func WithAPIKey(key string) OptsFunc {
return func(handler *PrivilegeHandler) {
handler.apiKey = key
}
}
// New creates a new PrivilegeHandler. Pass OptsFuncs to configure. // New creates a new PrivilegeHandler. Pass OptsFuncs to configure.
func New(opts ...OptsFunc) *PrivilegeHandler { func New(opts ...OptsFunc) *PrivilegeHandler {
handler := &PrivilegeHandler{ handler := &PrivilegeHandler{
@@ -57,7 +65,16 @@ func New(opts ...OptsFunc) *PrivilegeHandler {
// Fetch the initial set of privileges from an authz-service // Fetch the initial set of privileges from an authz-service
func (h *PrivilegeHandler) Fetch() error { func (h *PrivilegeHandler) Fetch() error {
resp, err := h.client.Get(fmt.Sprintf("%s/authz", h.baseURL)) req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/authz", h.baseURL), nil)
if err != nil {
return err
}
if h.apiKey != "" {
req.Header.Set("Authorization", "Bearer "+h.apiKey)
}
resp, err := h.client.Do(req)
if err != nil { if err != nil {
return err return err
} }
@@ -87,13 +104,14 @@ func (h *PrivilegeHandler) Setup() []goamqp.Setup {
// Process privilege-related events and update the internal state // Process privilege-related events and update the internal state
func (h *PrivilegeHandler) Process(msg interface{}, _ goamqp.Headers) (interface{}, error) { func (h *PrivilegeHandler) Process(msg interface{}, _ goamqp.Headers) (interface{}, error) {
h.Lock()
defer h.Unlock()
switch ev := msg.(type) { switch ev := msg.(type) {
case *UserAdded: case *UserAdded:
if priv, exists := h.privileges[ev.Email]; exists { if priv, exists := h.privileges[ev.Email]; exists {
priv[ev.CompanyID] = &CompanyPrivileges{} priv[ev.CompanyID] = &CompanyPrivileges{}
} else { } else {
h.Lock()
defer h.Unlock()
h.privileges[ev.Email] = map[string]*CompanyPrivileges{ h.privileges[ev.Email] = map[string]*CompanyPrivileges{
ev.CompanyID: {}, ev.CompanyID: {},
} }
@@ -101,19 +119,13 @@ func (h *PrivilegeHandler) Process(msg interface{}, _ goamqp.Headers) (interface
return nil, nil return nil, nil
case *UserRemoved: case *UserRemoved:
if priv, exists := h.privileges[ev.Email]; exists { if priv, exists := h.privileges[ev.Email]; exists {
h.Lock()
defer h.Unlock()
delete(priv, ev.CompanyID) delete(priv, ev.CompanyID)
} }
return nil, nil return nil, nil
case *PrivilegeAdded: case *PrivilegeAdded:
h.Lock()
defer h.Unlock()
h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, true) h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, true)
return nil, nil return nil, nil
case *PrivilegeRemoved: case *PrivilegeRemoved:
h.Lock()
defer h.Unlock()
h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, false) h.setPrivileges(ev.Email, ev.CompanyID, ev.Privilege, false)
return nil, nil return nil, nil
default: default:
+33
View File
@@ -251,6 +251,39 @@ func TestPrivilegeHandler_IsAllowed_Return_True_If_Privilege_Exists(t *testing.T
assert.True(t, result) assert.True(t, result)
} }
func TestPrivilegeHandler_Fetch_Sends_Authorization_Header_When_APIKey_Set(t *testing.T) {
var receivedAuth string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
receivedAuth = r.Header.Get("Authorization")
_, _ = w.Write([]byte("{}"))
}))
defer server.Close()
handler := New(
WithBaseURL(server.URL),
WithAPIKey("my-secret-key"),
)
err := handler.Fetch()
assert.NoError(t, err)
assert.Equal(t, "Bearer my-secret-key", receivedAuth)
}
func TestPrivilegeHandler_Fetch_No_Authorization_Header_Without_APIKey(t *testing.T) {
var receivedAuth string
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
receivedAuth = r.Header.Get("Authorization")
_, _ = w.Write([]byte("{}"))
}))
defer server.Close()
handler := New(WithBaseURL(server.URL))
err := handler.Fetch()
assert.NoError(t, err)
assert.Empty(t, receivedAuth)
}
func TestPrivilegeHandler_Fetch_Error_Response(t *testing.T) { func TestPrivilegeHandler_Fetch_Error_Response(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500) w.WriteHeader(500)
+1 -1
View File
@@ -2,7 +2,7 @@ module gitea.unbound.se/shiny/authz_client
go 1.22.12 go 1.22.12
toolchain go1.25.5 toolchain go1.26.2
require ( require (
github.com/sparetimecoders/goamqp v0.3.3 github.com/sparetimecoders/goamqp v0.3.3