fix: comprehensive audit fixes for issues #5, #8, #9, #10, #11, #12, #13#23
fix: comprehensive audit fixes for issues #5, #8, #9, #10, #11, #12, #13#23tsavo-at-pieces merged 4 commits intomainfrom
Conversation
- Replace shell-based computeFileHash in template_manifest.dart with pure-Dart crypto (fixes Windows where shasum/sha256sum don't exist) - Normalize CRLF to LF in _preserveUserSections to prevent silent data loss on Windows - Fix autodoc AccumulatorSink import error from recent crypto migration Fixes #11, fixes #8 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ::add-mask:: token masking before git config in all 3 skeleton locations and both ci.yaml locations (prevents PAT leaks in logs) - Add fetch-depth: 1 to all analyze/test checkout steps (saves 50-150s) - Replace /tmp/ with $RUNNER_TEMP for Windows compatibility - Add conditional artifact upload on test failure for diagnostics - Fix analysis cache key drift: add runner.arch to multi_platform block - Add sync-marker comments to all duplicated step sequences Fixes #10, fixes #13, partially addresses #12 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nfig() P0 coverage for validate(): - dart_sdk: missing, wrong type, empty, whitespace, channel vs semver - features: missing, wrong type, unknown keys (typo detection), non-bool - platforms: wrong type, unknown platform, valid single/multi - sub_packages: type validation, path traversal, duplicates, unsafe chars - secrets, pat_secret, line_length, runner_overrides P0 coverage for loadCiConfig(): - File missing, no ci key, valid ci section, malformed JSON, ci not a Map Partially addresses #5 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR SummaryMedium Risk Overview Hardens Written by Cursor Bugbot for commit e2cb4fc. Configure here. |
There was a problem hiding this comment.
Pull request overview
This PR addresses multiple items from the runtime_ci_tooling audit backlog by hardening config validation, improving cross-platform behavior (especially Windows), replacing shell-based hashing with pure Dart, and expanding unit test coverage for WorkflowGenerator.
Changes:
- Strengthen CI config validation (Dart SDK, feature keys, sub-packages, runner overrides) and normalize CRLF handling for preserved user sections.
- Replace template hashing shell-outs with
package:cryptoand adjust module hashing in autodoc. - Update CI workflow templates/workflows (token masking, shallow checkouts, RUNNER_TEMP usage, failure artifacts) and add a new comprehensive
WorkflowGeneratortest suite.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
lib/src/cli/utils/workflow_generator.dart |
Adds config validation hardening and CRLF normalization for user-section preservation. |
lib/src/cli/utils/template_manifest.dart |
Switches file hashing to pure-Dart SHA256 via package:crypto. |
lib/src/cli/commands/autodoc_command.dart |
Changes module hashing implementation to pure Dart (but now buffers all bytes in memory). |
lib/src/triage/utils/config.dart |
Hardens require_file handling with type checks and repo-root escape prevention. |
templates/github/workflows/ci.skeleton.yaml |
CI template updates for masking, checkout depth, temp paths, and failure artifacts (contains a matrix variable bug). |
.github/workflows/ci.yaml |
Applies the same CI improvements to this repository’s workflow. |
test/workflow_generator_test.dart |
Adds extensive tests for validate() and loadCiConfig() (contains Windows path portability issues). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - name: Upload test artifacts on failure | ||
| if: failure() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-artifacts-${{ matrix.os }} | ||
| path: | | ||
| test/integration/fixtures/bin/ | ||
| **/test-results/ | ||
| retention-days: 7 |
There was a problem hiding this comment.
In the multi_platform test job, the matrix include objects expose platform_id, runner, os_family, and arch, but this artifact name uses matrix.os which isn't defined. This will cause the step to fail at runtime. Use an existing key (e.g. matrix.platform_id) for the artifact name.
| - name: Analyze | ||
| run: | | ||
| dart analyze 2>&1 | tee /tmp/analysis.txt | ||
| if grep -q "^ error -" /tmp/analysis.txt; then | ||
| dart analyze 2>&1 | tee "$RUNNER_TEMP/analysis.txt" | ||
| if grep -q "^ error -" "$RUNNER_TEMP/analysis.txt"; then | ||
| echo "::error::Analysis errors found" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
This run: block uses bash syntax (| tee, if ...; then, grep -q) and references $RUNNER_TEMP, but the job runs on <%runner%> which can be a Windows runner in single-platform mode. On Windows the default shell is pwsh, so this step will fail. Consider setting shell: bash for these analyze steps (and any other bash-specific blocks) or rewriting them in a cross-shell way.
| - name: Analyze (<%name%>) | ||
| working-directory: <%path%> | ||
| run: | | ||
| GIT_LFS_SKIP_SMUDGE=1 dart pub get | ||
| dart analyze 2>&1 | tee /tmp/sub_analysis.txt | ||
| if grep -q "^ error -" /tmp/sub_analysis.txt; then | ||
| dart analyze 2>&1 | tee "$RUNNER_TEMP/sub_analysis.txt" | ||
| if grep -q "^ error -" "$RUNNER_TEMP/sub_analysis.txt"; then | ||
| echo "::error::Errors found in <%name%>" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
This sub-package analyze step uses bash-specific syntax (GIT_LFS_SKIP_SMUDGE=1 ..., | tee, if ...; then, grep -q) but doesn't specify shell: bash. If the single-platform workflow is generated for a Windows runner, this will fail under the default pwsh shell. Set shell: bash (or use env: + PowerShell-compatible commands) to make single-platform Windows generation work.
| final name = sp['name']; | ||
| final pathValue = sp['path']; | ||
| if (name is! String || name.trim().isEmpty) { | ||
| errors.add('ci.sub_packages[].name must be a non-empty string'); | ||
| } else if (!seenNames.add(name)) { | ||
| errors.add('ci.sub_packages contains duplicate name "$name"'); | ||
| } |
There was a problem hiding this comment.
sub_packages[].name is rendered unquoted into YAML (e.g. - name: Analyze (<%name%>)). Validation currently only checks non-empty, so values containing YAML-unsafe characters (like : or #) or leading/trailing whitespace can produce invalid YAML or confusing duplication behavior. Add validation that name is trimmed and restricts/disallows YAML-unsafe characters (at least :, #, newlines, \r, \t).
| test('returns null when config.json exists but has no "ci" key', () { | ||
| final configDir = Directory('${tempDir.path}/.runtime_ci')..createSync(); | ||
| File('${configDir.path}/config.json').writeAsStringSync(json.encode({ | ||
| 'repo_name': 'test_repo', | ||
| })); | ||
| final result = WorkflowGenerator.loadCiConfig(tempDir.path); | ||
| expect(result, isNull); | ||
| }); | ||
|
|
||
| test('returns the ci map when config.json has a valid "ci" section', () { | ||
| final configDir = Directory('${tempDir.path}/.runtime_ci')..createSync(); | ||
| File('${configDir.path}/config.json').writeAsStringSync(json.encode({ |
There was a problem hiding this comment.
This test builds paths using string interpolation with / (e.g. '${tempDir.path}/.runtime_ci'), which can break on Windows (mixed separators / escaping). Use package:path (e.g. p.join(tempDir.path, '.runtime_ci')) for cross-platform tests.
| final builder = BytesBuilder(copy: false); | ||
|
|
||
| for (final path in filePaths) { | ||
| // Include the path name in the digest so renames affect the hash. | ||
| input.add(utf8.encode(path)); | ||
| input.add(const [0]); | ||
| builder.add(utf8.encode(path)); | ||
| builder.addByte(0); | ||
|
|
||
| if (!path.startsWith('missing_dir:')) { | ||
| try { | ||
| input.add(File(path).readAsBytesSync()); | ||
| builder.add(File(path).readAsBytesSync()); | ||
| } catch (e) { | ||
| Logger.warn('Could not read $path for module hash: $e'); | ||
| } | ||
| } | ||
|
|
||
| input.add(const [0]); | ||
| builder.addByte(0); | ||
| } | ||
|
|
||
| input.close(); | ||
| return sink.events.single.toString(); | ||
| return sha256.convert(builder.takeBytes()).toString(); | ||
| } |
There was a problem hiding this comment.
_computeModuleHash now concatenates every file path and file's bytes into a single BytesBuilder before hashing. For large repos/modules this can significantly increase memory usage compared to streaming/chunked hashing. Consider using sha256.startChunkedConversion(...) (or another streaming approach) and add each file's bytes incrementally so the peak memory stays bounded.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
| if: failure() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-artifacts-${{ matrix.os }} |
There was a problem hiding this comment.
Skeleton template references non-existent matrix.os field
High Severity
In the multi-platform block, the new artifact upload step uses ${{ matrix.os }} but the generated matrix (from WorkflowGenerator) only contains keys platform_id, runner, os_family, and arch — there is no os field. This resolves to an empty string in GitHub Actions, so every matrix entry produces the artifact name test-artifacts-, causing name collisions and upload failures. The rendered ci.yaml for this repo correctly uses ${{ matrix.platform_id }}, but the skeleton template was not updated to match.
Integrate build_runner feature flag added in main into the CI skeleton template and test suite. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
## Changelog ## [0.14.0] - 2026-02-24 ### Added - Added `build_runner` feature flag for CI codegen to generate `.g.dart` files in CI instead of relying on local developer builds - Added `manage_cicd audit` and `audit-all` commands for `pubspec.yaml` dependency validation against `external_workspace_packages.yaml` registry (refs open-runtime/aot_monorepo#411) (#22) - Added sibling dependency conversion and per-package tag creation for multi-package releases, automatically converting bare sibling dependencies during release (#22) - Used org-managed runners as default platform definitions for Linux (`ubuntu-x64`/`arm64`) and Windows (`windows-x64`/`arm64`) ### Changed - Updated CI workflow templates and generator with latest patterns and removed deprecated config entries from templates (#22) ### Fixed - Fixed cross-platform hashing in `template_manifest.dart` using pure-Dart crypto and normalized CRLF to LF to prevent data loss on Windows (#23, fixes #5, #8, #10, #11, #12, #13) - Added strict input validation for `dart_sdk`, `feature` keys, `sub_packages`, and hardened triage config `require_file` to prevent path traversal - Replaced shell-based hashing with pure-Dart crypto in autodoc to ensure caching works on macOS, Windows, and minimal CI images - Normalized version input by stripping the leading 'v' prefix and validated SemVer in `create-release` - Fixed passing `allFindings` to `fixPubspec` and added `pub_semver` dependency - Validated YAML before writing and created backups in pubspec auditor to prevent corruption (#22) - Fixed tag existence checks by using `refs/tags/` prefix and handled errors for per-package tags (#22) - Increased test process timeout from 30 to 45 minutes to fix Windows named pipe tests on CI runners (#22) - Added `yaml_edit` dependency required for pubspec auditor ### Security - Added `::add-mask::` token masking before `git config` in all CI workflow locations to prevent Personal Access Token (PAT) leaks in logs, added `fetch-depth: 1` to checkout ... ## Files Modified ``` .../audit/v0.14.0/explore/breaking_changes.json | 4 + .../audit/v0.14.0/explore/commit_analysis.json | 122 +++++++++++++++++++++ .runtime_ci/audit/v0.14.0/explore/pr_data.json | 30 +++++ .runtime_ci/audit/v0.14.0/meta.json | 82 ++++++++++++++ .../v0.14.0/version_analysis/version_bump.json | 1 + .../version_analysis/version_bump_rationale.md | 26 +++++ .../release_notes/v0.14.0/changelog_entry.md | 24 ++++ .../release_notes/v0.14.0/contributors.json | 5 + .../release_notes/v0.14.0/linked_issues.json | 1 + .runtime_ci/release_notes/v0.14.0/release_notes.md | 59 ++++++++++ .../release_notes/v0.14.0/release_notes_body.md | 59 ++++++++++ .runtime_ci/version_bumps/v0.14.0.md | 26 +++++ CHANGELOG.md | 26 +++++ README.md | 14 ++- pubspec.yaml | 2 +- 15 files changed, 475 insertions(+), 6 deletions(-) ``` ## Version Bump Rationale # Version Bump Rationale **Decision**: minor **Why**: The recent commits introduce new capabilities, including a new `build_runner` feature flag for CI codegen and a new `audit-all` CLI command. These are backwards-compatible additive changes that expand the capabilities of the tooling without introducing breaking changes to existing public APIs or workflows, thereby warranting a minor version bump. **Key Changes**: - **New Feature**: Added `build_runner` feature flag for generating `.g.dart` files in CI to avoid environment drift and stale codegen risks. - **New Feature**: Added `audit-all` command to recursively audit all `pubspec.yaml` files under a directory against the package registry. - **Fix/Improvement**: Replaced shell-based file hashing with pure-Dart crypto for better cross-platform (Windows) compatibility. - **Security/CI Hardening**: Masked sensitive tokens in CI logs (`::add-mask::`), reduced checkout depth to 1 for faster executions, and migrated away from hardcoded... ## Contributors - @tsavo-at-pieces --- Automated release by CI/CD pipeline (Gemini CLI + GitHub Actions) Commits since v0.13.0: 15 Generated: 2026-02-24T20:32:27.206709Z


Summary
Comprehensive fix PR addressing 7 open issues from the runtime_ci_tooling audit backlog, plus input validation hardening. All changes verified with 113 passing tests and zero
dart analyzeissues.Fixes
sub_packagesvalidation tovalidate(): type checks, path traversal prevention, duplicate detection, safe character enforcement. Also addsdart_sdkchannel/semver validation and known feature key typo detection.computeFileHashintemplate_manifest.dartwith pure-Dartpackage:crypto. Fixes Windows whereshasum/sha256sumdon't exist._preserveUserSectionsto prevent silent user-section data loss on Windows.::add-mask::token masking before git config in all skeleton template locations andci.yaml. Prevents PAT leaks in CI logs.fetch-depth: 1on all analyze/test checkouts (saves 50-150s per run)$RUNNER_TEMPinstead of/tmp/for Windows compatibilityrunner.archmissing in multi_platform block). Added sync-marker comments to all duplicated step sequences for maintainability.workflow_generator_test.dartcovering all P0validate()rules andloadCiConfig()paths. Remaining:render(),_preserveUserSections(), and P1 tests.Also
AccumulatorSinkimport error inautodoc_command.dartfrom recent crypto migrationrequire_fileconfig: type guards, path canonicalization, repo-root escape preventionFiles Changed
lib/src/cli/utils/workflow_generator.dartlib/src/cli/utils/template_manifest.dartlib/src/cli/commands/autodoc_command.dartlib/src/triage/utils/config.darttemplates/github/workflows/ci.skeleton.yaml.github/workflows/ci.yamltest/workflow_generator_test.dartTest plan
dart analyze lib/— No issues founddart test— 113 tests passed (69 new + 44 existing)🤖 Generated with Claude Code