Skip to content

Commit 6ec39ff

Browse files
firecowmjncegodk
andauthored
Rewrite as standalone Go server with httputil.ReverseProxy (#4)
* Initial files * Initial commit * Remove weird readme.md * Fix release script * Fix release script * Try this release * Do not fail-fast * Try -- * Fix release * Add the token * Give it write perms * Fix release * Make sure network attachment match uses names instead of id * Use it as info * Use warn * Fix * Only publish linux amd64 * Rewrite as standalone Go server with httputil.ReverseProxy Replace Caddy plugin with a standalone HTTP server that properly handles Docker's connection hijacking for docker run/exec. * Use standardized CI workflow * Fix errcheck lint issues --------- Co-authored-by: Mads Jon Nielsen <mjn@cego.dk>
1 parent dcfabca commit 6ec39ff

15 files changed

Lines changed: 945 additions & 0 deletions

File tree

.github/workflows/qa.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, initial]
6+
pull_request:
7+
branches: [main, initial]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-24.04
12+
steps:
13+
- uses: actions/checkout@v4.2.2
14+
15+
- uses: actions/setup-go@v5.2.0
16+
with:
17+
go-version-file: go.mod
18+
19+
- name: Run tests
20+
run: go test -v -race ./...
21+
22+
lint:
23+
runs-on: ubuntu-24.04
24+
steps:
25+
- uses: actions/checkout@v4.2.2
26+
27+
- uses: actions/setup-go@v5.2.0
28+
with:
29+
go-version-file: go.mod
30+
31+
- name: golangci-lint
32+
uses: golangci/golangci-lint-action@v6.2.0
33+
with:
34+
version: v2.8.0
35+
36+
fmt:
37+
runs-on: ubuntu-24.04
38+
steps:
39+
- uses: actions/checkout@v4.2.2
40+
41+
- uses: actions/setup-go@v5.2.0
42+
with:
43+
go-version-file: go.mod
44+
45+
- name: Install golangci-lint
46+
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.8.0
47+
48+
- name: Check formatting
49+
run: test -z "$(golangci-lint fmt --diff)" || (echo "Run 'golangci-lint fmt' to fix formatting" && exit 1)
50+
51+
build:
52+
runs-on: ubuntu-24.04
53+
steps:
54+
- uses: actions/checkout@v4.2.2
55+
56+
- uses: actions/setup-go@v5.2.0
57+
with:
58+
go-version-file: go.mod
59+
60+
- name: Build
61+
run: go build -o docker-api-auth .

.github/workflows/release.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Release binaries
2+
3+
permissions:
4+
contents: write
5+
6+
on:
7+
release:
8+
types: [created]
9+
10+
jobs:
11+
releases-amd64:
12+
name: Release Go Binary AMD64
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Git checkout
16+
uses: actions/checkout@v5
17+
18+
- uses: actions/setup-go@v6
19+
with:
20+
go-version: stable
21+
22+
- name: Build
23+
run: CGO_ENABLED=0 go build -o docker-api-auth-linux-amd64 .
24+
25+
- name: Release
26+
uses: softprops/action-gh-release@v2
27+
with:
28+
files: docker-api-auth-linux-amd64

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.*
2+
docker-api-auth

example/acl.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
deployers:
3+
4+
- username: example
5+
password_hash: $2a$12$RvXRFK7mv.Q4M0ltpwLgL.tqBU2KkFV5i58q7AaDhbPOu9.DU.4qK
6+
service_prefix: example_
7+
network_attachments: [example-shared]

go.mod

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module github.com/cego/caddy-docker-api-auth
2+
3+
go 1.25.0
4+
5+
require (
6+
github.com/moby/moby/client v0.1.0-beta.0
7+
github.com/samber/lo v1.51.0
8+
github.com/stretchr/testify v1.10.0
9+
go.uber.org/zap v1.27.0
10+
golang.org/x/crypto v0.42.0
11+
gopkg.in/yaml.v3 v3.0.1
12+
)
13+
14+
require (
15+
github.com/Microsoft/go-winio v0.6.2 // indirect
16+
github.com/containerd/errdefs v1.0.0 // indirect
17+
github.com/containerd/errdefs/pkg v0.3.0 // indirect
18+
github.com/davecgh/go-spew v1.1.1 // indirect
19+
github.com/distribution/reference v0.6.0 // indirect
20+
github.com/docker/go-connections v0.6.0 // indirect
21+
github.com/docker/go-units v0.5.0 // indirect
22+
github.com/felixge/httpsnoop v1.0.4 // indirect
23+
github.com/go-logr/logr v1.4.2 // indirect
24+
github.com/go-logr/stdr v1.2.2 // indirect
25+
github.com/moby/docker-image-spec v1.3.1 // indirect
26+
github.com/moby/moby/api v1.52.0-beta.1 // indirect
27+
github.com/opencontainers/go-digest v1.0.0 // indirect
28+
github.com/opencontainers/image-spec v1.1.1 // indirect
29+
github.com/pmezard/go-difflib v1.0.0 // indirect
30+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
31+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
32+
go.opentelemetry.io/otel v1.35.0 // indirect
33+
go.opentelemetry.io/otel/metric v1.35.0 // indirect
34+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
35+
go.uber.org/multierr v1.10.0 // indirect
36+
golang.org/x/sys v0.36.0 // indirect
37+
golang.org/x/text v0.29.0 // indirect
38+
)

go.sum

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
2+
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
3+
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
4+
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
5+
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
6+
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
7+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
8+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
9+
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
10+
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
11+
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
12+
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
13+
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
14+
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
15+
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
16+
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
17+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
18+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
19+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
20+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
21+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
22+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
23+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
24+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
25+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
26+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
27+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
28+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
29+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
30+
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
31+
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
32+
github.com/moby/moby/api v1.52.0-beta.1 h1:r5U4U72E7xSHh4zX72ndY1mA/FOGiAPiGiz2a8rBW+w=
33+
github.com/moby/moby/api v1.52.0-beta.1/go.mod h1:8sBV0soUREiudtow4vqJGOxa4GyHI5vLQmvgKdHq5Ok=
34+
github.com/moby/moby/client v0.1.0-beta.0 h1:eXzrwi0YkzLvezOBKHafvAWNmH1B9HFh4n13yb2QgFE=
35+
github.com/moby/moby/client v0.1.0-beta.0/go.mod h1:irAv8jRi4yKKBeND96Y+3AM9ers+KaJYk9Vmcm7loxs=
36+
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
37+
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
38+
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
39+
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
40+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
41+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
42+
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
43+
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
44+
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
45+
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
46+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
47+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
48+
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
49+
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
50+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
51+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
52+
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
53+
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
54+
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
55+
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
56+
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
57+
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
58+
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
59+
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
60+
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
61+
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
62+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
63+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
64+
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
65+
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
66+
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
67+
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
68+
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
69+
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
70+
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
71+
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
72+
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
73+
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
74+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
75+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
76+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
77+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
78+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
79+
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
80+
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
81+
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
82+
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=

internal/acl.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package internal
2+
3+
import (
4+
"os"
5+
"regexp"
6+
7+
"github.com/samber/lo"
8+
"golang.org/x/crypto/bcrypt"
9+
"gopkg.in/yaml.v3"
10+
)
11+
12+
type ACLDeployer struct {
13+
servicePrefixRegexp *regexp.Regexp
14+
15+
Username string `yaml:"username"`
16+
PasswordHash string `yaml:"password_hash"`
17+
ServicePrefix string `yaml:"service_prefix"`
18+
NetworkAttachments []string `yaml:"network_attachments"`
19+
}
20+
21+
type ACL struct {
22+
Deployers []*ACLDeployer `json:"deployers"`
23+
}
24+
25+
func NewACL(aclFilePath string) *ACL {
26+
acl := &ACL{}
27+
28+
out := MustReturn(os.ReadFile(aclFilePath))
29+
MustNotFail(yaml.Unmarshal(out, &acl))
30+
31+
// Compile and assign regexp's
32+
for _, deployer := range acl.Deployers {
33+
deployer.servicePrefixRegexp = MustReturn(regexp.Compile("^" + deployer.ServicePrefix))
34+
}
35+
36+
return acl
37+
}
38+
39+
func (a *ACL) VerifyUser(username string, password string) bool {
40+
matches := lo.Filter(a.Deployers, func(item *ACLDeployer, _ int) bool {
41+
if item.Username != username {
42+
return false
43+
}
44+
45+
err := bcrypt.CompareHashAndPassword([]byte(item.PasswordHash), []byte(password))
46+
return err == nil
47+
})
48+
return len(matches) > 0
49+
}
50+
51+
func (a *ACL) MatchNetworkAttachment(username string, networkName string) bool {
52+
matches := lo.Filter(a.Deployers, func(item *ACLDeployer, _ int) bool {
53+
if item.Username != username {
54+
return false
55+
}
56+
57+
networkMatches := lo.Filter(item.NetworkAttachments, func(item string, _ int) bool {
58+
return item == networkName
59+
})
60+
return len(networkMatches) > 0
61+
})
62+
return len(matches) > 0
63+
}
64+
65+
func (a *ACL) MatchServicePrefix(username string, serviceName string) bool {
66+
matches := lo.Filter(a.Deployers, func(item *ACLDeployer, _ int) bool {
67+
if item.Username != username {
68+
return false
69+
}
70+
71+
return item.servicePrefixRegexp.MatchString(serviceName)
72+
})
73+
return len(matches) > 0
74+
}

internal/acl_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package internal_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/cego/caddy-docker-api-auth/internal"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestACL(t *testing.T) {
11+
acl := internal.NewACL("../example/acl.yml")
12+
13+
validExampleUsername := "example"
14+
validExamplePassword := "see im a proper password"
15+
validExamplePrefix := "example_"
16+
17+
t.Run("it passes VerifyUser", func(t *testing.T) {
18+
found := acl.VerifyUser(validExampleUsername, validExamplePassword)
19+
assert.True(t, found)
20+
})
21+
22+
t.Run("it fails VerifyUser with invalid password", func(t *testing.T) {
23+
found := acl.VerifyUser(validExampleUsername, "im not a proper password")
24+
assert.False(t, found)
25+
})
26+
27+
t.Run("it fails VerifyUser with invalid username", func(t *testing.T) {
28+
found := acl.VerifyUser("notavalidusername", validExamplePassword)
29+
assert.False(t, found)
30+
})
31+
32+
t.Run("it matches by username and service name", func(t *testing.T) {
33+
found := acl.MatchServicePrefix(validExampleUsername, validExamplePrefix)
34+
assert.True(t, found)
35+
})
36+
t.Run("it matches by username, but not service name", func(t *testing.T) {
37+
found := acl.MatchServicePrefix(validExampleUsername, "notexample_")
38+
assert.False(t, found)
39+
})
40+
t.Run("it matches by service name, but not username", func(t *testing.T) {
41+
found := acl.MatchServicePrefix("invalid-username", validExamplePrefix)
42+
assert.False(t, found)
43+
})
44+
}

0 commit comments

Comments
 (0)