Skip to content

fix(EC-1993): reject past --effective-time values by default#3424

Open
cuipinghuo wants to merge 1 commit into
conforma:mainfrom
cuipinghuo:forbid-setting-effective-time
Open

fix(EC-1993): reject past --effective-time values by default#3424
cuipinghuo wants to merge 1 commit into
conforma:mainfrom
cuipinghuo:forbid-setting-effective-time

Conversation

@cuipinghuo

@cuipinghuo cuipinghuo commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Backdating --effective-time suppresses time-gated security rules at both
the CLI level (severity demotion) and the Rego level (when_ns
propagation). Reject effective-time values more than 5 minutes in the
past unless --allow-past-effective-time is explicitly set.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

What:

  • Add validation in parseEffectiveTime() to reject times >5min in the past
  • Add --allow-past-effective-time flag to validate image, validate input, and compare commands
  • 5-minute grace period to accommodate clock skew

Why:

  • Setting --effective-time to a past date demotes time-gated rule failures to warnings (CLI level)
    and shifts the time reference for all Rego rules via when_ns (Rego level), effectively bypassing
    security checks at the integration test gate where users control IntegrationTestScenario params

Tickets:

  Backdating --effective-time suppresses time-gated security rules at both
  the CLI level (severity demotion) and the Rego level (when_ns
  propagation). Reject effective-time values more than 5 minutes in the
  past unless --allow-past-effective-time is explicitly set.

  Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 20, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:26 PM UTC · Completed 6:31 PM UTC
Commit: 87c4a29 · View workflow run →

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The change adds --allow-past-effective-time to compare, image validation, and input validation commands. Policy parsing now rejects timestamps beyond a five-minute grace period unless enabled, with tests covering the new behavior and updated constructor calls.

Changes

Effective-time control

Layer / File(s) Summary
Policy effective-time validation
internal/policy/policy.go, internal/policy/policy_test.go
Policy options and constructors propagate past-time allowance; parsing enforces the five-minute grace period and tests cover accepted and rejected timestamps.
CLI flag wiring
cmd/compare/compare.go, cmd/validate/image.go, cmd/validate/input.go
The three commands register --allow-past-effective-time and pass its value into effective-time validation.
Consumer and behavior test updates
cmd/validate/image_test.go, internal/input/*_test.go
Tests update policy constructor calls and exercise commands with past effective times.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant validateImageCmd
  participant policy.NewPolicy
  participant parseEffectiveTime
  participant rejectPastTime
  validateImageCmd->>policy.NewPolicy: pass AllowPastEffectiveTime
  policy.NewPolicy->>parseEffectiveTime: parse EffectiveTime
  parseEffectiveTime->>rejectPastTime: validate timestamp
  rejectPastTime-->>parseEffectiveTime: accept or return error
Loading

Suggested reviewers: simonbaird

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: rejecting past --effective-time values by default.
Description check ✅ Passed The description follows the required What, Why, and Tickets sections and explains the change and rationale.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@fullsend-ai-review

Copy link
Copy Markdown

Review — comment

PR: fix(EC-1993): reject past --effective-time values by default

Summary

This PR adds a security mitigation to prevent users from backdating --effective-time to values more than 5 minutes in the past, which could suppress time-gated security rules at both the CLI level (severity demotion) and the Rego level (when_ns propagation). A new --allow-past-effective-time boolean flag provides an explicit override.

The core logic in internal/policy/policy.go is well-structured: a dedicated rejectPastTime function, a pastEffectiveTimeGracePeriod constant, and clean integration into both RFC3339 and date-only parse paths. The flag is consistently wired through all three commands (validate image, validate input, compare). Test coverage for the core behavior in TestParseEffectiveTimePastRejection is thorough and covers boundary conditions.

Findings

1. Duplicate effective-time validation in compare.go — medium / correctness

cmd/compare/compare.go implements its own past-time rejection logic (diff lines 100–105) independently from the shared rejectPastTime function and pastEffectiveTimeGracePeriod constant in internal/policy/policy.go:

// compare.go — inline, untestable
threshold := time.Now().UTC().Add(-5 * time.Minute)

// policy.go — shared constant, mockable clock
threshold := now().UTC().Add(-pastEffectiveTimeGracePeriod)

This creates two maintenance concerns:

  1. Duplicated threshold: The 5-minute window is a constant in policy.go but hardcoded inline in compare.go. Future threshold changes must be updated in two places, with no compiler or test to catch a drift.
  2. Untestable clock: compare.go calls time.Now() directly instead of the package-level now() function from the policy package, making it impossible to mock time in tests. There is no test coverage for this new validation path in compare.go.

Remediation: Consider refactoring compare.go to delegate effective-time parsing to a shared utility (e.g., exporting ParseAndValidateEffectiveTime from the policy package), or at minimum reference the existing constant and add test coverage for the compare command's validation path.

Positive observations

  • The rejectPastTime function in policy.go is clean, well-placed, and called from both the RFC3339 and date-only parse paths.
  • NewOfflinePolicy correctly passes allowPast: true, preserving backward compatibility for offline scenarios that may need arbitrary time evaluation.
  • All NewInputPolicy call sites (including internal/input/report_test.go, internal/input/validate_test.go, and internal/policy/policy_test.go) are updated consistently with the new parameter.
  • The Options struct uses the zero value (false) as the safe default for AllowPastEffectiveTime, so existing callers of NewPolicy get the restrictive behavior automatically.
  • TestParseEffectiveTimePastRejection provides comprehensive coverage: past dates rejected, grace period boundaries, allowPast=true override, future dates accepted, and "now"/"attestation" unaffected.
  • Existing tests that use past dates (e.g., TestNewPolicy, TestPreProcessPolicy) are correctly updated with AllowPastEffectiveTime: true.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread cmd/compare/compare.go
if err != nil {
return fmt.Errorf("invalid effective time format: %w", err)
}
if !allowPastEffectiveTime {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] correctness

Duplicate effective-time validation: compare.go implements its own past-time rejection using time.Now() directly and a hardcoded 5-minute threshold, independently from the shared rejectPastTime function and pastEffectiveTimeGracePeriod constant in internal/policy/policy.go. This creates two places to maintain the threshold (risking drift) and prevents clock-mocking in tests. No test coverage exists for this code path in compare.go.

Suggested fix: Refactor to delegate effective-time parsing to a shared utility from the policy package (e.g., export ParseAndValidateEffectiveTime), or at minimum reference the existing pastEffectiveTimeGracePeriod constant and add test coverage for the compare command validation path.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

requires-manual-review Review requires human judgment size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant