From 7b5c1285a25671c2d0b1f1ce726108ef7c2a27fa Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 1 Nov 2026 19:25:15 +0000 Subject: [PATCH] Exclude forge contracts from runtime dependencies --- docs/roadmap/remediation.md | 7 ++++++- internal/apicheck/main.go | 2 +- internal/apicheck/main_test.go | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md index 466ffcc..87a468c 100644 --- a/docs/roadmap/remediation.md +++ b/docs/roadmap/remediation.md @@ -81,7 +81,12 @@ it adds no token-format restriction, remote permission requirement, or probe. ## 2. Protect the runtime boundary from the new forge contract — P2 -Status: open. +Status: complete. + +**Completed:** Added `forge` to the runtime dependency exclusions and covered +both direct and transitive forbidden dependencies with focused graph fixtures. +The complete checker test package and the actual compiled API/dependency check +passed; the current runtime dependency graph remains accepted. **Evidence:** [dependency checker](../../internal/apicheck/main.go), especially `forbiddenRuntimeDependency`, and the runtime boundary in diff --git a/internal/apicheck/main.go b/internal/apicheck/main.go index 0269e13..c3dd107 100644 --- a/internal/apicheck/main.go +++ b/internal/apicheck/main.go @@ -281,7 +281,7 @@ func commandInternalRoot(path string) string { func forbiddenRuntimeDependency(path string) bool { for _, part := range strings.Split(strings.ToLower(path), "/") { switch part { - case "orchestration", "orchestrator", "engine", "release", "process", "build", "builder", "gitea", "delivery", "cli": + case "orchestration", "orchestrator", "engine", "release", "process", "build", "builder", "gitea", "forge", "delivery", "cli": return true } } diff --git a/internal/apicheck/main_test.go b/internal/apicheck/main_test.go index 769358a..763327b 100644 --- a/internal/apicheck/main_test.go +++ b/internal/apicheck/main_test.go @@ -10,6 +10,26 @@ import ( "testing" ) +func TestRuntimeFacadeCannotDependOnForge(t *testing.T) { + for _, indirect := range []bool{false, true} { + name := "direct" + dependency := modulePath + "/internal/forge" + packages := []listedPackage{{ImportPath: dependency}} + if indirect { + name = "transitive" + packages = append(packages, listedPackage{ImportPath: modulePath + "/internal/runtime", Imports: []string{dependency}}) + dependency = modulePath + "/internal/runtime" + } + packages = append(packages, listedPackage{ImportPath: modulePath + "/buildinfo", Imports: []string{dependency}}) + t.Run(name, func(t *testing.T) { + err := checkImportDirections(packages) + if err == nil || !strings.Contains(err.Error(), "buildinfo") || !strings.Contains(err.Error(), "/internal/forge") { + t.Fatalf("dependency check = %v, want excluded forge runtime dependency", err) + } + }) + } +} + func TestExportedContractBoundaries(t *testing.T) { tests := []struct { name string