Skip to content

Add sink-visibility runtime verification and integration tests#8903

Merged
lpcox merged 1 commit into
mainfrom
sink-visibility-integration-tests
Jul 8, 2026
Merged

Add sink-visibility runtime verification and integration tests#8903
lpcox merged 1 commit into
mainfrom
sink-visibility-integration-tests

Conversation

@lpcox

@lpcox lpcox commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds runtime repo visibility verification as defense-in-depth for the sink-visibility feature (#8895), plus comprehensive integration tests.

Runtime Verification

At gateway startup, when a write-sink guard has sink-visibility configured, the gateway now verifies the actual repo visibility via GET /repos/{owner}/{repo}:

  • If the API reports the repo is public but config says private/internal → overrides to "public" with warning:
    SINK VISIBILITY OVERRIDE: configured="private" but runtime check shows repo test-owner/test-repo is "public" — overriding to "public" to prevent potential data exfiltration
    
  • Catches repos made public after workflow compilation (stale config)
  • Gracefully skipped when GITHUB_REPOSITORY or GitHub token unavailable
  • Falls back to configured value on API errors (non-fatal)
  • Never relaxes: if configured as "public" but repo is actually private, keeps "public"

Integration Tests

7 test groups with 20+ subtests covering:

Test What it verifies
ConfigAccepted Gateway starts with valid sink-visibility values (public, private, internal, omitted, case-insensitive)
InvalidValue Invalid values cause noop guard fallback
RuntimeOverride Override warning emitted when repo is more public than configured
RuntimeCheckSkippedWithoutRepo Graceful skip when GITHUB_REPOSITORY unset
RuntimeCheckSkippedWithoutToken Graceful skip when no token available
RuntimeCheckAPIFailure Graceful fallback on API 500 errors
WriteSinkGuardLogsSinkVisibility Effective visibility logged at startup

Files

  • internal/githubhttp/visibility.goFetchRepoVisibility and VerifySinkVisibility functions
  • internal/githubhttp/visibility_test.go — Unit tests for the visibility API client
  • internal/server/guard_init.goverifySinkVisibilityAtRuntime method wired into guard creation
  • test/integration/sink_visibility_test.go — Integration tests using mock HTTP backends + mock GitHub API
  • docs/CONFIGURATION.md — Added "Runtime Verification" documentation section

Related

- Add runtime repo visibility check via GitHub API at gateway startup
- Override configured sink-visibility to 'public' with warning if repo
  is actually public (defense-in-depth against stale compile-time config)
- Gracefully skip check when GITHUB_REPOSITORY or token unavailable
- Fall back to configured value on API errors (non-fatal)
- Add FetchRepoVisibility and VerifySinkVisibility in githubhttp package
- Add comprehensive integration tests covering:
  - Valid config acceptance (public/private/internal/omitted/case-insensitive)
  - Invalid values fall back to noop guard
  - Runtime override emits warning when repo more public than configured
  - Runtime check skipped without GITHUB_REPOSITORY
  - Runtime check skipped without GitHub token
  - API failure graceful fallback
  - Effective sink-visibility logged correctly

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 8, 2026 02:26
@lpcox
lpcox merged commit ded09a6 into main Jul 8, 2026
31 checks passed
@lpcox
lpcox deleted the sink-visibility-integration-tests branch July 8, 2026 02:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a defense-in-depth runtime check for the write-sink guard’s sink-visibility by querying the GitHub repos API at startup, and introduces unit + integration test coverage to validate override/skip/fallback behavior.

Changes:

  • Add GitHub API helper functions to fetch repository visibility and compute an effective sink visibility.
  • Wire runtime sink-visibility verification into write-sink guard creation during server startup.
  • Add unit tests for the GitHub visibility client and a comprehensive integration test suite for sink-visibility scenarios.
Show a summary per file
File Description
test/integration/sink_visibility_test.go New integration tests covering accepted/invalid values and runtime verification outcomes (override/skip/fallback).
internal/server/guard_init.go Adds runtime verification hook when constructing the write-sink guard.
internal/githubhttp/visibility.go New GitHub API client helpers: fetch repo visibility and compute effective sink-visibility.
internal/githubhttp/visibility_test.go Unit tests validating visibility parsing and verification logic.
docs/CONFIGURATION.md Documents the new runtime verification behavior for sink-visibility.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 3
  • Review effort level: Low

Comment on lines +393 to +398
func (us *UnifiedServer) verifySinkVisibilityAtRuntime(serverID, configuredVisibility string) string {
nwo := os.Getenv("GITHUB_REPOSITORY")
if nwo == "" {
logGuardInit.Printf("sink-visibility runtime check skipped: GITHUB_REPOSITORY not set (serverID=%s)", serverID)
return configuredVisibility
}
Comment on lines +111 to +116
// If actual is "public" but configured is not "public" (or unset),
// 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
}
Comment on lines +118 to +126
// 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
lpcox added a commit that referenced this pull request Jul 8, 2026
## Summary

Addresses the three review feedback items from #8903 for the
sink-visibility runtime verification.

## Changes

### 1. Skip runtime check when sink-visibility is omitted

When `sink-visibility` is not explicitly configured (empty string), the
runtime API check is now skipped entirely. This preserves the documented
backward-compatible behavior where omitted sink-visibility uses accept
patterns without any surprise upgrade to "public".

**Before**: Omitted config + public repo → runtime check overrides to
"public" (breaking backward compat)
**After**: Omitted config → runtime check skipped, accept patterns used
as-is

### 2. Remove duplicate logging from `VerifySinkVisibility`

The helper function no longer logs override warnings via
`logger.LogWarn`. All logging is now handled by the caller
(`verifySinkVisibilityAtRuntime`) which has the `serverID` context for
proper correlation.

### 3. Return configured value when no override needed

`VerifySinkVisibility` now returns the configured value unchanged in all
non-override cases, instead of returning the actual API visibility. This
prevents policy drift where `configured="private"` but
`actual="internal"` would have returned "internal".

**Before**: configured="private", actual="internal" → returns "internal"
**After**: configured="private", actual="internal" → returns "private"
(unchanged)

The only case that changes the return value is the security-critical
one: repo is actually public but config doesn't say "public".

## Testing

All integration tests and unit tests pass, including the existing
sink-visibility test suite.

## Related

- #8903 — Original PR with review comments
huangyingting pushed a commit to repomesh/gh-aw-mcpg that referenced this pull request Jul 8, 2026
- Skip runtime check when sink-visibility is omitted (empty string),
  preserving backward-compatible behavior for legacy configs
- Remove duplicate logging from VerifySinkVisibility helper; let the
  caller (verifySinkVisibilityAtRuntime) handle all logging with
  serverID context
- Return configured value when no override is needed, instead of
  returning the actual API value which could drift from compiler config
  (e.g. configured='private' but actual='internal' no longer returns
  'internal')

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants