diff --git a/internal/githubhttp/visibility.go b/internal/githubhttp/visibility.go index ecf9b2fb..3b1ba15a 100644 --- a/internal/githubhttp/visibility.go +++ b/internal/githubhttp/visibility.go @@ -87,12 +87,12 @@ func FetchRepoVisibility(ctx context.Context, apiBaseURL, nwo, authHeader string } // VerifySinkVisibility compares the configured sink-visibility against the -// actual repository visibility from the GitHub API. If the actual visibility -// is more public than configured, it returns the actual (more restrictive) -// visibility to prevent exfiltration. +// actual repository visibility from the GitHub API. Only overrides the +// configured value in the security-critical case: repo is actually public +// but config doesn't say "public". // // Returns: -// - The effective visibility to use (may override configured value) +// - The effective visibility to use (configured value unless overridden to "public") // - Whether an override occurred // - Any error encountered (non-fatal — callers should log and use configured value) func VerifySinkVisibility(ctx context.Context, apiBaseURL, nwo, authHeader, configuredVisibility string) (string, bool, error) { @@ -105,23 +105,18 @@ func VerifySinkVisibility(ctx context.Context, apiBaseURL, nwo, authHeader, conf return configuredVisibility, false, err } - actualStr := string(actual) configured := strings.ToLower(strings.TrimSpace(configuredVisibility)) - // If actual is "public" but configured is not "public" (or unset), + // If actual is "public" but configured is not "public", // override to "public" — this is the security-critical case. if actual == RepoVisibilityPublic && configured != "public" { - logger.LogWarn("difc", "Sink visibility override: configured=%q but repo %s is actually PUBLIC — overriding to \"public\" to prevent exfiltration", configured, nwo) - return actualStr, true, nil + return "public", true, nil } - // If configured says public but actual says private/internal, - // keep "public" (the more restrictive setting) — defense in depth. - if configured == "public" && actual != RepoVisibilityPublic { - logVisibility.Printf("Sink visibility: configured=public but repo %s is %s — keeping public (more restrictive)", nwo, actual) - return "public", false, nil - } - - logVisibility.Printf("Sink visibility verified: configured=%q, actual=%s — no override needed", configured, actual) - return actualStr, false, nil + // All other cases: return the configured value unchanged. + // This includes: + // - configured="public" but actual=private → keep "public" (more restrictive) + // - configured="private" and actual=private → no change needed + // - configured="internal" and actual=internal → no change needed + return configured, false, nil } diff --git a/internal/githubhttp/visibility_test.go b/internal/githubhttp/visibility_test.go index 70eed79f..6e8e01cb 100644 --- a/internal/githubhttp/visibility_test.go +++ b/internal/githubhttp/visibility_test.go @@ -170,7 +170,7 @@ func TestVerifySinkVisibility(t *testing.T) { configured: "private", actualVis: "internal", actualPrivate: true, - wantEffective: "internal", + wantEffective: "private", wantOverridden: false, }, } diff --git a/internal/server/guard_init.go b/internal/server/guard_init.go index 0babf4d3..a3d4cf42 100644 --- a/internal/server/guard_init.go +++ b/internal/server/guard_init.go @@ -391,6 +391,14 @@ func (us *UnifiedServer) getTrustedBots() []string { // Emits a warning when overriding the configured value. // Falls back to the configured value on any API error (non-fatal). func (us *UnifiedServer) verifySinkVisibilityAtRuntime(serverID, configuredVisibility string) string { + // Skip runtime check when sink-visibility is not explicitly configured. + // This preserves backward-compatible behavior where omitted sink-visibility + // uses accept patterns without any override. + if configuredVisibility == "" { + logGuardInit.Printf("sink-visibility runtime check skipped: sink-visibility not configured (serverID=%s)", serverID) + return configuredVisibility + } + nwo := os.Getenv("GITHUB_REPOSITORY") if nwo == "" { logGuardInit.Printf("sink-visibility runtime check skipped: GITHUB_REPOSITORY not set (serverID=%s)", serverID)