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
18 changes: 17 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,20 @@ jobs:

- uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: profile.cov
path-to-profile: profile.cov

integration-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.24

- name: Run integration tests
working-directory: integration_test
run: |
go test -tags integration -v -count=1 -timeout 10m ./...
95 changes: 95 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

VCVerifier is a FIWARE component implementing SIOP-2/OIDC4VP authentication flows. It exchanges Verifiable Credentials (VCs) for JWTs, enabling VC-based authentication and authorization. Supports multiple trust frameworks (EBSI, Gaia-X) and credential formats (JSON-LD VCs, SD-JWTs).

## Build & Test Commands

```bash
# Build
go build -o VCVerifier .

# Run all tests
go test ./... -v

# Run all tests with coverage
go test ./... -v -coverprofile=profile.cov

# Run tests for a single package
go test ./verifier/... -v

# Run a specific test
go test ./verifier/... -v -run TestVerifyConfig

# Docker build (multi-platform)
docker build -t vcverifier .
```

There is no Makefile or linter configuration. CI runs `go test ./... -v` with Go 1.24.

## Configuration

Runtime config is loaded from `server.yaml` (override with `CONFIG_FILE` env var). The config is parsed by `config.ReadConfig()` using gookit/config with YAML driver and mapstructure tags.

Key config sections: `server` (port, timeouts, template/static dirs), `logging`, `verifier` (DID, TIR address, policies, validation mode, key algorithm), `ssiKit` (auditor URL), `configRepo` (dynamic service configurations with scopes and trust endpoints).

## Architecture

**Entry point**: `main.go` — reads config, initializes logging and verifier, sets up Gin router with routes from `openapi/`, serves on configured port with graceful shutdown.

### Package Responsibilities

- **`verifier/`** — Core package (~1500 lines in `verifier.go`). Session management, JWT creation (RS256/ES256), QR code generation, nonce/state management. Request object modes: `urlEncoded`, `byValue`, `byReference`. Also contains:
- `presentation_parser.go` — Parses VP tokens (JSON-LD and SD-JWT formats), JSON-LD document loading with caching
- `jwt_verifier.go` — VC validation with modes: `none`, `combined`, `jsonLd`, `baseContext`. DID verification method resolution for did:key, did:web, did:jwk
- `trustedissuer.go` / `trustedparticipant.go` — EBSI registry verification
- `compliance.go` — Policy compliance checking (signatures, dates, etc.)
- `holder.go` — Holder verification
- `gaiax.go` — Gaia-X compliance checks
- `elsi_proof_checker.go` — JAdES signature validation for did:elsi
- `credentialsConfig.go` — Credential configuration management
- `caching_client.go` — HTTP caching layer

- **`openapi/`** — HTTP handlers generated from OpenAPI spec (`api/api.yaml`). Routes defined in `routers.go`. Handlers in `api_api.go` (token, authorization, authentication) and `api_frontend.go` (frontend endpoints, WebSocket polling).

- **`tir/`** — Trusted Issuers Registry client. Queries EBSI v3/v4 endpoints, caches results. Includes M2M auth via `tokenProvider.go` and `authorizationClient.go`.

- **`gaiax/`** — Gaia-X compliance client. did:web resolution, X.509 certificate chain validation, trust anchor verification.

- **`jades/`** — JAdES signature validation for did:elsi credentials.

- **`config/`** — Configuration structs and YAML parsing. Test fixtures in `config/data/`.

- **`logging/`** — Zap-based structured logging with Gin middleware integration.

- **`common/`** — Shared types: cache interfaces (ServiceCache, TirEndpoints, IssuersCache), clock utilities, HTTP helpers, token signer interfaces.

- **`views/`** — HTML templates and static assets for QR code presentation frontend.

### Request Flow

1. Client hits OpenAPI endpoints (`/api/v1/authorization`, `/token`, etc.)
2. `openapi/` handlers delegate to `verifier/` for session management and credential exchange
3. Verifier validates presentations using the VC verification chain (parsing, signature validation, policy compliance, trust registry checks)
4. Trust anchors are consulted via `tir/` (EBSI) or `gaiax/` clients
5. On success, a JWT is issued to the client

## Testing Patterns

- Uses `github.com/stretchr/testify` for assertions
- Table-driven tests with `type test struct` and `t.Run()` loops
- Mock implementations within test files (e.g., `mockNonceGenerator`, `mockSessionCache`)
- Test fixtures in `config/data/` (YAML files)
- Logging is initialized in tests with a shared `LOGGING_CONFIG` variable

## Key Dependencies

- **trustbloc/vc-go, did-go, kms-go** — VC verification, DID resolution, key management
- **gin-gonic/gin** — HTTP framework
- **lestrrat-go/jwx/v3** — JWT/JWS/JWK handling
- **piprate/json-gold** — JSON-LD processing
- **gookit/config** — Configuration management
- **foolin/goview** — Template rendering for Gin
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ VCVerifier provides the necessary endpoints(see [API](./api/api.yaml)) to offer
* [API](#api)
* [Open Issues](#open-issues)
* [Testing](#testing)
* [Unit Tests](#unit-tests)
* [Integration Tests](#integration-tests)
* [License](#license)

## Background
Expand Down Expand Up @@ -427,8 +429,98 @@ The VCVerifier does currently not support all functionalities defined in the con

## Testing

### Unit Tests

Functionality of the verifier is tested via parameterized Unit-Tests, following golang-bestpractices. In addition, the verifier is integrated into the [VC-Integration-Test](https://github.com/fiware/VC-Integration-Test), involving all components used in a typical, VerifiableCredentials based, scenario.

Run unit tests:
```shell
go test ./... -v
```

### Integration Tests

A black-box integration test suite lives in `integration_test/`. It builds the verifier binary, launches it as a subprocess with generated YAML configs, and interacts purely over HTTP — no internal Go imports from verifier packages. Tests are gated behind the `integration` build tag so they never run during regular `go test ./...`.

#### Running

By default, the test suite builds the verifier binary from source. You can override this with environment variables to test a pre-built binary instead:

| Environment Variable | Description |
|----------------------|-------------|
| `VERIFIER_BINARY` | Path to a local pre-built verifier binary |
| `VERIFIER_BINARY_URL` | URL to download a verifier binary from (made executable automatically) |

If both are set, `VERIFIER_BINARY` takes precedence.

```shell
# All integration tests (builds from source)
cd integration_test && go test -tags integration -v -count=1 ./...

# Test a pre-built local binary
VERIFIER_BINARY=/path/to/vcverifier go test -tags integration -v -count=1 ./...

# Test a binary downloaded from a URL
VERIFIER_BINARY_URL=https://example.com/releases/vcverifier-linux-amd64 \
go test -tags integration -v -count=1 ./...

# By category
go test -tags integration -v -count=1 -run TestM2M ./...
go test -tags integration -v -count=1 -run TestFrontendV2 ./...
go test -tags integration -v -count=1 -run TestDeeplink ./...
go test -tags integration -v -count=1 -run TestEndpoints ./...
```

#### Test Categories

| Category | Tests | Description |
|----------|-------|-------------|
| M2M Success | 7 | VP-token-to-JWT exchange with JWT-VC, SD-JWT, did:key, did:web, cnf/claim holder verification |
| M2M Failure | 6 | Rejection of invalid credentials, untrusted issuers, signature mismatches |
| Frontend V2 | 2 | Cross-device flow with QR code, WebSocket notifications, authorization code exchange |
| Deeplink | 2 | Same-device flow with openid4vp:// redirects and 302 authentication responses |
| Endpoints | 8 | JWKS, OpenID configuration, health check, and parameter validation errors |

#### How to Add a New Test

1. **Pick or create a test file.** Each file covers a flow category (e.g., `m2m_test.go`, `deeplink_test.go`). Every file must start with `//go:build integration`.

2. **Create a fixture function** that sets up identities, a mock TIR, a verifier config, and starts the verifier process. Follow the pattern in existing `setup*` functions:

```go
func setupMyTest(t *testing.T) *myFixture {
t.Helper()
issuer, _ := helpers.GenerateDidKeyIdentity()
tirServer := helpers.NewMockTIR(map[string]helpers.TrustedIssuer{ /* ... */ })
port, _ := helpers.GetFreePort()
keyPath, _ := helpers.GenerateSigningKeyPEM(t.TempDir())
config := helpers.NewConfigBuilder(port, tirServer.URL).
WithSigningKey(keyPath).
WithService(serviceID, scopeName, "DEEPLINK").
WithCredential(serviceID, scopeName, "MyCredential", tirServer.URL).
Build()
vp, _ := helpers.StartVerifier(config, projectRoot, binaryPath)
return &myFixture{verifier: vp, cleanup: func() { vp.Stop(); tirServer.Close() }}
}
```

3. **Write the test function.** Use parameterized sub-tests (`t.Run`) when testing multiple variations. Interact with the verifier only via HTTP. Call `defer fixture.cleanup()` to stop the verifier after the test.

4. **Use the helper library** in `integration_test/helpers/`:
- `identity.go` — Generate `did:key` and `did:web` identities
- `credentials.go` — Create JWT-VC, SD-JWT, VP tokens, and DCQL responses
- `config.go` — Fluent `ConfigBuilder` for verifier YAML configs
- `process.go` — Build, start, health-poll, and stop the verifier binary
- `tir_mock.go` — Mock Trusted Issuers Registry
- `did_web_mock.go` — Mock `did:web` TLS server

5. **Run your new test** in isolation first, then as part of the full suite:
```shell
cd integration_test
go test -tags integration -v -count=1 -run TestMyNewTest ./...
go test -tags integration -v -count=1 ./...
```


## License

Expand Down
58 changes: 58 additions & 0 deletions RELEASE_NOTES_INTEGRATION_TESTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Release Notes: Integration Test Framework

## Overview

A comprehensive black-box integration test framework for VCVerifier, treating the verifier as an opaque HTTP service. The test suite builds the verifier binary, launches it as a subprocess with generated YAML configs, and interacts purely over HTTP — no internal Go imports from verifier packages.

## New Files

### Test helpers (`integration_test/helpers/`)

- **`process.go`** — Build, launch, health-poll, and graceful shutdown of the verifier binary
- **`config.go`** — Fluent `ConfigBuilder` API for generating YAML configs with DCQL, holder verification, JWT inclusion, trusted participants
- **`identity.go`** — `TestIdentity` generation for `did:key` and `did:web` (ECDSA P-256)
- **`credentials.go`** — JWT-VC, SD-JWT, VP token, and DCQL response creation with cryptographic signing
- **`tir_mock.go`** — Mock Trusted Issuers Registry (`httptest.Server`) with percent-encoded DID support
- **`did_web_mock.go`** — Mock `did:web` TLS server with dynamic DID document serving

### Test files

- **`m2m_test.go`** — 7 parameterized M2M success tests (JWT-VC, SD-JWT, did:key, did:web, cnf holder, claim holder)
- **`m2m_failure_test.go`** — 6 parameterized M2M failure tests (wrong type, missing claims, untrusted issuer, invalid VP signature, invalid cnf, invalid claim holder)
- **`frontend_v2_test.go`** — 2 end-to-end Frontend V2 cross-device tests (byReference, byValue) with WebSocket
- **`deeplink_test.go`** — 2 end-to-end Deeplink same-device tests (byReference, byValue)
- **`endpoints_test.go`** — 8 endpoint validation tests (JWKS, OpenID config, health, error cases)
- **`helpers_test.go`** — Unit tests for the helper functions themselves

## Test Coverage Summary

| Category | Tests | Description |
|----------|-------|-------------|
| M2M Success | 7 | VP-token-to-JWT exchange with various credential formats and DID methods |
| M2M Failure | 6 | Rejection of invalid credentials, untrusted issuers, signature mismatches |
| Frontend V2 | 2 | Cross-device flow with QR code, WebSocket notifications, authorization code exchange |
| Deeplink | 2 | Same-device flow with openid4vp:// redirects and 302 authentication responses |
| Endpoints | 8 | JWKS, OpenID configuration, health check, and parameter validation errors |
| **Total** | **25** | |

## Dependencies Added (integration_test/go.mod only)

- `github.com/gorilla/websocket` — WebSocket client for Frontend V2 cross-device flow tests
- `github.com/lestrrat-go/jwx/v3` — JWT/JWK creation and verification
- `github.com/trustbloc/kms-go` — did:key identity generation
- `github.com/stretchr/testify` — Test assertions

## Running

```bash
# All integration tests
cd integration_test && go test -tags integration -v -count=1 ./...

# By category
go test -tags integration -v -count=1 -run TestM2M ./...
go test -tags integration -v -count=1 -run TestFrontendV2 ./...
go test -tags integration -v -count=1 -run TestDeeplink ./...
go test -tags integration -v -count=1 -run TestEndpoints ./...
```

The `integration` build tag ensures these tests don't run during regular `go test ./...`.
Loading
Loading