feat(#143): fetch doc-map config from trusted VCS ref
The doc-map YAML config was previously read from the local workspace (the PR branch checkout). A malicious PR author could modify .review-bot/doc-map.yml to map any path glob to sensitive design docs, causing review-bot to fetch and inject those docs into the LLM prompt. Fix: add --doc-map-trusted-ref (DOC_MAP_TRUSTED_REF) flag. When set to a trusted ref (e.g. 'main'), the doc-map config is fetched from the VCS API at that ref instead of from local workspace. A 404 from VCS is a hard error (no silent fallback to local copy). When unset, the local workspace is used with a security warning in the logs pointing operators to the new flag. Changes: - review/docmap.go: add ParseDocMapConfigContent + parseDocMapBytes helper to parse from in-memory content (fetched via VCS API) - cmd/review-bot/main.go: add --doc-map-trusted-ref flag; Step 6c branches on trusted-ref to fetch vs local-workspace load - .gitea/actions/review/action.yml: add doc-map-trusted-ref input - README.md: document new input - CHANGELOG.md: security and feature entries Tests: - TestParseDocMapConfigContent_Valid/Empty/InvalidYAML/UnknownKeys in review/docmap_test.go Coverage: 53.0% cmd/review-bot
This commit is contained in:
+18
-2
@@ -52,15 +52,31 @@ func ParseDocMapConfig(localPath string) (*DocMapConfig, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read doc-map file %q: %w", localPath, err)
|
||||
}
|
||||
return parseDocMapBytes(data, localPath)
|
||||
}
|
||||
|
||||
// ParseDocMapConfigContent parses a doc-map YAML config from an in-memory
|
||||
// string. The source parameter is used only for error messages and log entries
|
||||
// (e.g. "main:main@<ref>").
|
||||
//
|
||||
// Use this when the config content has been fetched from a trusted VCS ref
|
||||
// rather than read from the local workspace.
|
||||
func ParseDocMapConfigContent(content, source string) (*DocMapConfig, error) {
|
||||
data := []byte(content)
|
||||
return parseDocMapBytes(data, source)
|
||||
}
|
||||
|
||||
// parseDocMapBytes is the shared YAML parse implementation used by
|
||||
// ParseDocMapConfig and ParseDocMapConfigContent.
|
||||
func parseDocMapBytes(data []byte, source string) (*DocMapConfig, error) {
|
||||
var cfg DocMapConfig
|
||||
if err := yaml.UnmarshalWithOptions(data, &cfg, yaml.Strict()); err != nil {
|
||||
// Re-parse without strict mode to log which keys are unknown.
|
||||
var relaxed DocMapConfig
|
||||
if err2 := yaml.Unmarshal(data, &relaxed); err2 != nil {
|
||||
return nil, fmt.Errorf("parse doc-map YAML %q: %w", localPath, err)
|
||||
return nil, fmt.Errorf("parse doc-map YAML %q: %w", source, err)
|
||||
}
|
||||
slog.Warn("doc-map YAML contains unknown keys (ignored)", "file", localPath, "error", err)
|
||||
slog.Warn("doc-map YAML contains unknown keys (ignored)", "file", source, "error", err)
|
||||
cfg = relaxed
|
||||
}
|
||||
return &cfg, nil
|
||||
|
||||
Reference in New Issue
Block a user