fix(cli): reject invalid date bounds - #1604
Conversation
Validate --since and --until as documented full-date formats, reject impossible calendar dates, and apply the same validation to config-file bounds. Keep the accepted formats and non-zero rejection behavior documented for scripts and users. Co-authored-by: dok123 <[email protected]>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 5fc0736 | Commit Preview URL Branch Preview URL |
Aug 15 2026, 12:52 PM |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesDate-bound validation
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: ⚪ Minimal · up to The change rejects invalid date bounds and applies the same validation to configuration files; no actionable merge-blocking risk remains beyond normal checks and review. Sequence Diagram(s)sequenceDiagram
participant CLIParser
participant normalize_date_bound
participant ConfigContext
CLIParser->>normalize_date_bound: validate CLI since/until value
normalize_date_bound-->>CLIParser: YYYYMMDD or parse error
ConfigContext->>normalize_date_bound: validate configured since/until value
normalize_date_bound-->>ConfigContext: YYYYMMDD or configuration error
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Important
This PR still allows some invalid config bounds to bypass rejection. Please address the inline findings before merging.
Reviewed changes — Reviewed the complete date-bound validation change across the CLI parser, shared normalization, config loading, tests, and documentation.
- CLI bound validation — Restricts
--sinceand--untilto the two documented formats and real calendar dates, then normalizes them toYYYYMMDD. - Config bound validation — Adds config-file validation and normalization while keeping named pi-store errors command-gated.
- Regression coverage and documentation — Adds parser, CLI helper, config, and core test coverage and documents rejection behavior.
@v0 or keep the SHA fresh with Dependabot | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
1 issue found across 8 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="rust/crates/ccusage-config/src/config.rs">
<violation number="1" location="rust/crates/ccusage-config/src/config.rs:70">
P2: When an invalid `since`/`until` sits in `defaults` but a command-specific map in the same config overrides it with a valid value, the effective bound is valid yet `detect_date_bound_error` flags the overridden default first and `config_error()` rejects the whole invocation. It returns on the first invalid map instead of skipping values that a later, higher-precedence map overrides, while `apply_config_to_shared` lets that later map win. Consider validating the final effective bound (or skipping invalid values that a subsequent map overrides) so a valid command override is not spuriously rejected.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| /// so the check runs here and surfaces through `config_error` for every | ||
| /// command that applies shared options, not just the pi-store readers. | ||
| fn detect_date_bound_error(&self) -> Option<String> { | ||
| self.option_maps().into_iter().find_map(|options| { |
There was a problem hiding this comment.
P2: When an invalid since/until sits in defaults but a command-specific map in the same config overrides it with a valid value, the effective bound is valid yet detect_date_bound_error flags the overridden default first and config_error() rejects the whole invocation. It returns on the first invalid map instead of skipping values that a later, higher-precedence map overrides, while apply_config_to_shared lets that later map win. Consider validating the final effective bound (or skipping invalid values that a subsequent map overrides) so a valid command override is not spuriously rejected.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At rust/crates/ccusage-config/src/config.rs, line 70:
<comment>When an invalid `since`/`until` sits in `defaults` but a command-specific map in the same config overrides it with a valid value, the effective bound is valid yet `detect_date_bound_error` flags the overridden default first and `config_error()` rejects the whole invocation. It returns on the first invalid map instead of skipping values that a later, higher-precedence map overrides, while `apply_config_to_shared` lets that later map win. Consider validating the final effective bound (or skipping invalid values that a subsequent map overrides) so a valid command override is not spuriously rejected.</comment>
<file context>
@@ -29,25 +29,57 @@ pub struct ConfigContext {
+ /// so the check runs here and surfaces through `config_error` for every
+ /// command that applies shared options, not just the pi-store readers.
+ fn detect_date_bound_error(&self) -> Option<String> {
+ self.option_maps().into_iter().find_map(|options| {
+ let options = SharedOptions::from_map(options);
+ [("since", options.since), ("until", options.until)]
</file context>
ccusage
@ccusage/ccusage-darwin-arm64
@ccusage/ccusage-darwin-x64
@ccusage/ccusage-linux-arm64
@ccusage/ccusage-linux-x64
@ccusage/ccusage-win32-x64
commit: |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Reject non-string config bounds and keep command detection aligned with root options that consume values. Add regressions for both paths so invalid date-bound configuration cannot be silently ignored. Co-authored-by: dok123 <[email protected]>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Reviewed the commits since the prior Pullfrog review, focusing on raw config-bound validation and command detection around root options.
- Rejected wrong-typed config bounds — Validated raw JSON values before typed option conversion so present non-string
sinceanduntilvalues now fail throughconfig_error. - Preserved command-specific validation — Classified root value-taking
--lastand--sectionsoptions so command maps remain correctly selected when those options precede the report command. - Retained date validation behavior — Confirmed the shared normalization, parser rejection, config handling, and regression tests remain consistent for documented formats and real calendar dates.
@v0 or keep the SHA fresh with Dependabot | View workflow run | Using GPT Luna (free via Pullfrog for OSS) | 𝕏
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |

Summary
Testing
Closes #1483
Summary by cubic
Rejects invalid date bounds in the CLI and config to prevent silent mis-filtering. Previously we accepted any string and stripped dashes; now we accept only real calendar dates in YYYY-MM-DD or YYYYMMDD and exit non-zero otherwise.
since/until; non-string values and invalid dates error viaconfig_errorfor any command that applies shared options. Named pi-store errors remain gated to relevant commands.--last,--sections) so per-command config cannot bypass date checks.DATE_BOUND_FORMATSfromccusage-cli;normalize_date_boundnow returnsOption<String>and is used byccusage-cli-parserandccusage-config.Migration
YYYY-MM-DDorYYYYMMDDonly; remove slashes/timestamps and fix impossible dates.since/untilare strings; numeric values like 20260710 will now fail.Written for commit 5fc0736. Summary will update on new commits.
Summary by CodeRabbit
New Features
YYYY-MM-DDandYYYYMMDDformats.Bug Fixes
Documentation