Skip to content

feat(lint): introduce structured-first lint validation#65

Merged
ghaskins merged 3 commits intomanetu:mainfrom
ghaskins:lint-enhancements
Apr 8, 2026
Merged

feat(lint): introduce structured-first lint validation#65
ghaskins merged 3 commits intomanetu:mainfrom
ghaskins:lint-enhancements

Conversation

@ghaskins
Copy link
Copy Markdown
Contributor

@ghaskins ghaskins commented Apr 7, 2026

Add a new pkg/policydomain/lint package that exposes a Lint() function returning []Diagnostic — a unified type carrying file path, line/column, severity, entity context, and source category. This allows third-party consumers (e.g. CodeMirror editors) to use the same validation logic as the CLI and implement their own frontend.

Key changes:

  • Diagnostic type: Source, Severity, Location{File,Start{Line,Col}}, Entity{Domain,Type,ID,Field}, Message, Category
  • YAML validation preserves line numbers from yaml.v3 error strings
  • Rego AST parse errors now expose ast.Error.Location.{Row,Col}
  • Regal violations map synthetic-file lines back to YAML file lines via computeRegoOffsets() (yaml.Node tree walk)
  • OPA check replaced with in-process ast.CompileModules — no more shell-out to opa check, errors carry line/col from ast.Errors
  • registry.NewRegistryPermissive() loads domains without fail-fast on validation errors so all phases can run even when refs are broken
  • mpe lint CLI rewritten as a thin Diagnostic formatter, same output
  • Regal tests skip gracefully under GODEBUG=fips140=only (OPA crypto.md5 is not FIPS-safe; this was a pre-existing upstream limitation)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

@ghaskins ghaskins force-pushed the lint-enhancements branch from d9f7356 to 2b4a3f2 Compare April 7, 2026 20:35
…n/lint

Add a new pkg/policydomain/lint package that exposes a Lint() function
returning []Diagnostic — a unified type carrying file path, line/column,
severity, entity context, and source category. This allows third-party
consumers (e.g. CodeMirror editors) to use the same validation logic as
the CLI and implement their own frontend.

Key changes:
- Diagnostic type: Source, Severity, Location{File,Start{Line,Col}},
  Entity{Domain,Type,ID,Field}, Message, Category
- YAML validation preserves line numbers from yaml.v3 error strings
- Rego AST parse errors now expose ast.Error.Location.{Row,Col}
- Regal violations map synthetic-file lines back to YAML file lines
  via computeRegoOffsets() (yaml.Node tree walk)
- OPA check replaced with in-process ast.CompileModules — no more
  shell-out to opa check, errors carry line/col from ast.Errors
- registry.NewRegistryPermissive() loads domains without fail-fast on
  validation errors so all phases can run even when refs are broken
- mpe lint CLI rewritten as a thin Diagnostic formatter, same output
- Regal tests skip gracefully under GODEBUG=fips140=only (OPA crypto.md5
  is not FIPS-safe; this was a pre-existing upstream limitation)

Signed-off-by: Greg Haskins <greg@manetu.com>
@ghaskins ghaskins force-pushed the lint-enhancements branch from 2b4a3f2 to 6b567a6 Compare April 7, 2026 22:41
@ghaskins ghaskins marked this pull request as ready for review April 7, 2026 22:42
- Add SourceRegistry diagnostic source for domain-loading errors that are
  not YAML syntax failures (e.g. unknown apiVersion, wrong kind)
- Surface parsers.LoadFromBytes errors as SourceRegistry diagnostics
  instead of silently skipping the file
- Fix registry creation error diagnostic from misleading SourceYAML to
  SourceRegistry
- Guard regoOffsets map lookups against nil in opacheck.go and regal.go
  (explicit nil check makes fallback intent clear)
- Add RegalTimeout to Options (default 60 s) and apply context.WithTimeout
  before calling Regal to prevent indefinite hangs
- Export SyntheticRegoName so it can be unit-tested directly
- Centralize mapper fallback ID format in mapperFallbackID() helper,
  eliminating the three-way duplication across rego, opacheck, and regal
- Rename LintFromStrings parameter files → contents for clarity
- Add tests: TestSyntheticRegoName, TestLintFromStrings_AllInvalidYAML,
  TestLintFromStrings_UnknownAPIVersion

Signed-off-by: Greg Haskins <greg@manetu.com>
muralisrini
muralisrini previously approved these changes Apr 7, 2026
core.go had 0% coverage because all existing tests called plint.Lint()
directly, bypassing Execute() entirely. This adds an executeCmd() helper
that constructs a real cli.Command with the lint subcommand's flags and
drives Execute() end-to-end.

Integration tests via executeCmd():
- No files specified -> error
- Valid file, multiple valid files -> success paths
- Unsupported file extension (.json) -> warning + skip
- --no-opa-flags, --opa-flags explicit, MPE_CLI_OPA_FLAGS env var
- Invalid YAML, bad Rego, OPA check failure, reference error
- --regal with violations (printResult Regal-violations path)
- --regal with no Rego (printResult Regal-passed path)

Direct unit tests for unexported helpers (same-package access):
- TestRegalTitle: both branches (with/without colon separator)
- TestPrintDiagnostic_AllSources: SourceYAML, SourceCycle, SourceRego
  without line, SourceOPACheck without line, SourceRegal without entity,
  and the empty-file "unknown" fallback
- TestPrintResult_NoFileDiagnostics: byFile[""] path for no-file diagnostics
- TestPrintFileSuccesses_ParseFailure: parsers.Load error -> "Valid YAML"
- TestPrintFileSuccesses_MapperNoID: mapper with no name/mrn -> "mapper[N]"

Result: core.go coverage 0% -> 99.1% (only unreachable TOCTOU path remains)
Signed-off-by: Greg Haskins <greg@manetu.com>
@ghaskins ghaskins merged commit 48d43d6 into manetu:main Apr 8, 2026
17 checks passed
@ghaskins ghaskins deleted the lint-enhancements branch April 8, 2026 01:55
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