diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index e0d1df4b3c..0000000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-version: 2.1
-
-workflows:
- tests:
- jobs:
- - build
- - report:
- requires:
- - build
-orbs:
- qlty: qltysh/qlty-orb@0.0
-jobs:
- build:
- parallelism: 8
- docker:
- - image: cimg/go:1.26
- steps:
- - checkout
-
- - restore_cache:
- keys:
- - go-mod-v2-{{ checksum "go.sum" }}
-
- - run: go get -t -v ./...
-
- - save_cache:
- key: go-mod-v2-{{ checksum "go.sum" }}
- paths:
- - "/go/pkg/mod"
-
- - run: mkdir cov
- - run: go test -p 1 -v $(go list ./... | circleci tests split) -race -coverprofile=cov/c_raw_$CIRCLE_NODE_INDEX.out
- - persist_to_workspace:
- root: .
- paths:
- - cov
-
- report:
- docker:
- - image: cimg/go:1.26
- steps:
- - checkout
- - attach_workspace:
- at: .
- - run:
- name: Merge test files
- command: |
- cat "cov/c_raw_0.out" >> c_raw.out
- for f in $(seq 1 7)
- do
- tail -n +2 "cov/c_raw_$f.out" >> c_raw.out
- done
- - run:
- name: Remove test, mock and generated code
- command: |
- cat c_raw.out | grep -v generated | grep -v mock | grep -v test > c.out
- # Qlty Coverage Orb
- - qlty/coverage_publish:
- files: c.out
- format: coverprofile
diff --git a/.github/workflows/go-test.yaml b/.github/workflows/go-test.yaml
new file mode 100644
index 0000000000..90a8dbb9df
--- /dev/null
+++ b/.github/workflows/go-test.yaml
@@ -0,0 +1,38 @@
+name: 'Go test'
+
+on:
+ push:
+ branches:
+ - 'master'
+ - 'V*'
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+
+ - name: Set up Go
+ uses: actions/setup-go@v6
+ with:
+ go-version-file: 'go.mod'
+
+ - name: Test
+ run: go test -p 1 ./... -race -coverprofile=c_raw.out
+
+ - name: Filter coverage
+ run: grep -v generated c_raw.out | grep -v mock | grep -v test > c.out
+
+ - name: Upload coverage to Qlty
+ uses: qltysh/qlty-action/coverage@a19242102d17e497f437d7466aa01b528537e899 # v2.2.0
+ with:
+ oidc: true
+ files: c.out
+ format: coverprofile
diff --git a/README.rst b/README.rst
index dfb0847da7..b01864c2d6 100644
--- a/README.rst
+++ b/README.rst
@@ -7,8 +7,8 @@ It contains all the necessary components for secure discovery and authorization.
See the `documentation `_ for how to set up, integrate and use the Nuts node.
-.. image:: https://circleci.com/gh/nuts-foundation/nuts-node.svg?style=svg
- :target: https://circleci.com/gh/nuts-foundation/nuts-node
+.. image:: https://github.com/nuts-foundation/nuts-node/actions/workflows/go-test.yaml/badge.svg
+ :target: https://github.com/nuts-foundation/nuts-node/actions/workflows/go-test.yaml
:alt: Build Status
.. image:: https://readthedocs.org/projects/nuts-node/badge/?version=latest
diff --git a/README_template.rst b/README_template.rst
index 1ff1dcc22b..b2f71317c6 100644
--- a/README_template.rst
+++ b/README_template.rst
@@ -7,8 +7,8 @@ It contains all the necessary components for secure discovery and authorization.
See the `documentation `_ for how to set up, integrate and use the Nuts node.
-.. image:: https://circleci.com/gh/nuts-foundation/nuts-node.svg?style=svg
- :target: https://circleci.com/gh/nuts-foundation/nuts-node
+.. image:: https://github.com/nuts-foundation/nuts-node/actions/workflows/go-test.yaml/badge.svg
+ :target: https://github.com/nuts-foundation/nuts-node/actions/workflows/go-test.yaml
:alt: Build Status
.. image:: https://readthedocs.org/projects/nuts-node/badge/?version=latest
diff --git a/crypto/storage/vault/vault_test.go b/crypto/storage/vault/vault_test.go
index cf7db0ea9f..57b9095d03 100644
--- a/crypto/storage/vault/vault_test.go
+++ b/crypto/storage/vault/vault_test.go
@@ -292,7 +292,6 @@ func TestNewVaultKVStorage(t *testing.T) {
t.Run("error - wrong URL", func(t *testing.T) {
storage, err := NewVaultKVStorage(Config{Address: "http://non-existing"})
require.Error(t, err)
- assert.Regexp(t, `no such host|Temporary failure in name resolution`, err.Error())
assert.Nil(t, storage)
})
}
diff --git a/didman/api/v1/client_test.go b/didman/api/v1/client_test.go
index db74049406..3520f291a5 100644
--- a/didman/api/v1/client_test.go
+++ b/didman/api/v1/client_test.go
@@ -115,7 +115,7 @@ func TestHTTPClient_AddEndpoint(t *testing.T) {
Address: "not_an_address", Timeout: time.Second},
}
endpoint, err := c.AddEndpoint("abc", "type", "some-url")
- assert.Regexp(t, `no such host|Temporary failure in name resolution`, err.Error())
+ assert.Error(t, err)
assert.Nil(t, endpoint)
})
}
@@ -139,7 +139,7 @@ func TestHTTPClient_DeleteEndpointsByType(t *testing.T) {
Address: "not_an_address", Timeout: time.Second},
}
err := c.DeleteEndpointsByType("did:nuts:123", "eOverdracht")
- assert.Regexp(t, `no such host|Temporary failure in name resolution`, err.Error())
+ assert.Error(t, err)
})
}
@@ -228,7 +228,7 @@ func TestHTTPClient_GetCompoundServices(t *testing.T) {
Address: "not_an_address", Timeout: time.Second},
}
res, err := c.GetCompoundServices("did:nuts:123")
- assert.Regexp(t, `no such host|Temporary failure in name resolution`, err.Error())
+ assert.Error(t, err)
assert.Nil(t, res)
})
diff --git a/policy/local.go b/policy/local.go
index 81719eb7d8..66e462b1ee 100644
--- a/policy/local.go
+++ b/policy/local.go
@@ -87,22 +87,14 @@ func (b *LocalPDP) PresentationDefinitions(_ context.Context, scope string) (pe.
return result, nil
}
-// loadFromDirectory traverses all .json files in the given directory and loads them
+// loadFromDirectory traverses all .json files in the given directory and loads them.
+// Entries are processed in lexical order so duplicate-scope detection is deterministic.
func (b *LocalPDP) loadFromDirectory(directory string) error {
- // open the directory
- dir, err := os.Open(directory)
+ files, err := os.ReadDir(directory)
if err != nil {
return err
}
- defer dir.Close()
- // read all the files in the directory
- files, err := dir.Readdir(0)
- if err != nil {
- return err
- }
-
- // load all the files
for _, file := range files {
if file.IsDir() {
continue