Critical fixes: - F-01: SatScope array form support (single pointer → slice with polymorphic JSON) - F-02: Add governance-intent@guildhouse.dev as 10th Shellstream extension - F-06: Replace os.Exit(1) stubs with go-plugin Serve() boilerplate in all cmd/ - F-13: Validate SatScope.ResourcePattern is non-empty High priority: - F-03: Add normative Accord policy syntax note to credential-governance.md §8.2 - F-04: Replace OID XXXXX placeholder with explicit PEN reference and IANA TODO - F-05: Document CredentialComposer hook mapping in spec and plugin-types.md - F-07/F-08: Commit CI pipeline (.github/workflows/ci.yaml) - F-09: Add hashicorp/go-plugin v1.6.3 to go.mod Medium priority: - F-10: Wire sample-ssh-cert-extensions.json fixture into shellstream tests - F-11: Cross-reference merkle proof depth limit (256 leaves) in governance spec - F-12: Add YAML format clarification headers to deploy configs - F-14: Expand README with project status, docs links, and quick-start Low priority: - F-15: Standardize "SSH SVID" → "SSH-SVID" terminology across docs - F-16: Add GovernanceEpochSeconds to PluginConfig and deploy configs - F-17: Add troubleshooting section to deployment.md, error handling to OIDC docs Global: Rename all extension keys from @guildhouse.io to @guildhouse.dev Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
105 lines
3.5 KiB
Markdown
105 lines
3.5 KiB
Markdown
# Testing Strategy
|
|
|
|
How to test the Guildhouse SPIRE plugins.
|
|
|
|
## Running Tests
|
|
|
|
```bash
|
|
make test # Run all tests
|
|
make lint # Run go vet
|
|
|
|
# Verbose output
|
|
go test -v ./...
|
|
|
|
# Single package
|
|
go test -v ./pkg/shellstream/...
|
|
|
|
# With coverage
|
|
go test -coverprofile=coverage.out ./...
|
|
go tool cover -html=coverage.out
|
|
```
|
|
|
|
## Test Structure
|
|
|
|
### Unit Tests (`pkg/`)
|
|
|
|
Each package has `*_test.go` files with unit tests:
|
|
|
|
| Package | Tests | Coverage Focus |
|
|
|---------|-------|---------------|
|
|
| `pkg/shellstream` | ~28 tests | Encode/decode round-trips, validation rules, format constraints, co-occurrence rules |
|
|
| `pkg/oidc` | 2 tests | Config validation (scaffolded) |
|
|
| `pkg/governance` | 2 tests | Client construction (scaffolded) |
|
|
| `pkg/sshcert` | 3 tests | Builder config validation (scaffolded) |
|
|
| `pkg/config` | 2 tests | Plugin config validation (scaffolded) |
|
|
|
|
### `pkg/shellstream` Tests (Fully Implemented)
|
|
|
|
The shellstream package has comprehensive tests covering:
|
|
|
|
- **Round-trip**: Encode → Decode produces identical values (full and minimal)
|
|
- **Required fields**: Missing tenant-id, missing roles produce validation errors
|
|
- **Format validation**: Invalid UUID, wrong hex length, uppercase hex, invalid base64
|
|
- **Co-occurrence**: sat-scope without sat-hash, ceremony-id without ceremony-type, merkle-proof without merkle-root
|
|
- **Parsing**: JSON sat-scope, comma-separated roles, base64 merkle proof, uint64 governance epoch
|
|
- **Edge cases**: Epoch value 0, nil extensions, unknown extensions ignored
|
|
- **Enum validation**: Unknown ceremony-type rejected
|
|
|
|
### Integration Test Approach (Future)
|
|
|
|
When plugin implementations are complete, integration tests will use mock gRPC servers:
|
|
|
|
```go
|
|
// Example mock GovernanceService
|
|
type mockGovernanceServer struct {
|
|
quartermasterv1.UnimplementedGovernanceServiceServer
|
|
intents map[string]*Intent
|
|
}
|
|
|
|
func (s *mockGovernanceServer) CreateIntent(ctx context.Context, req *quartermasterv1.CreateIntentRequest) (*quartermasterv1.CreateIntentResponse, error) {
|
|
// Return predictable responses for testing
|
|
}
|
|
```
|
|
|
|
Integration tests will:
|
|
1. Start mock gRPC servers for GovernanceService, CeremonyService, NotaryService
|
|
2. Create plugin instances pointed at the mock servers
|
|
3. Invoke plugin methods (Attest, Compose, Notify)
|
|
4. Verify the plugin made expected gRPC calls with correct parameters
|
|
5. Verify the plugin handled error conditions (unreachable service, denied intent, ceremony timeout)
|
|
|
|
## Test Fixtures
|
|
|
|
Test fixture files in `test/fixtures/`:
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `sample-oidc-token.json` | Example OIDC token payload for oidc-attestor testing |
|
|
| `sample-sat-scope.json` | Example SatScope for governance client testing |
|
|
| `sample-ssh-cert-extensions.json` | Example Shellstream extensions map for shellstream package testing |
|
|
| `spire-test-config.hcl` | Example SPIRE plugin configuration for config package testing |
|
|
|
|
Load fixtures in tests:
|
|
|
|
```go
|
|
func loadFixture(t *testing.T, name string) []byte {
|
|
t.Helper()
|
|
data, err := os.ReadFile(filepath.Join("../../test/fixtures", name))
|
|
if err != nil {
|
|
t.Fatalf("load fixture %s: %v", name, err)
|
|
}
|
|
return data
|
|
}
|
|
```
|
|
|
|
## CI Pipeline
|
|
|
|
The CI pipeline is defined in `.github/workflows/ci.yaml`. It runs on every push and pull request to `master`:
|
|
|
|
1. Checks out the repository
|
|
2. Sets up Go 1.23
|
|
3. Runs `make test` (all unit tests)
|
|
4. Runs `make lint` (`go vet`)
|
|
5. Runs `make build` (compiles all 4 plugin binaries)
|
|
|
|
See [`.github/workflows/ci.yaml`](../.github/workflows/ci.yaml) for the full workflow definition.
|