capture-file: constrain globs to the project root - #1146
Draft
shunichironomura wants to merge 4 commits into
Draft
shunichironomura wants to merge 4 commits into
shunichironomura wants to merge 4 commits into
Conversation
This was referenced Jul 22, 2026
2 tasks
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 22, 2026 10:42
76650da to
242cc6c
Compare
shunichironomura
force-pushed
the
capture-file-project-containment
branch
from
July 22, 2026 10:42
605680b to
284bbe6
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## project-relative-path #1146 +/- ##
=========================================================
+ Coverage 54.61% 55.33% +0.72%
=========================================================
Files 42 42
Lines 4283 4384 +101
=========================================================
+ Hits 2339 2426 +87
- Misses 1944 1958 +14 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 22, 2026 22:53
242cc6c to
0806b44
Compare
shunichironomura
force-pushed
the
capture-file-project-containment
branch
from
July 22, 2026 22:53
284bbe6 to
1d0437b
Compare
2 tasks
shunsuke-shimomura
added a commit
that referenced
this pull request
Aug 5, 2026
Add a pull command that downloads a run from a Capsula server and restores it under the local vault, as the counterpart of capsula push (#1177): - Extend GET /api/v1/runs/{id} with a files array (path, size, hash); the server-internal storage_path is not exposed - Reconstruct the run directory deterministically from the run's ULID and name via the new capsula_core::run::run_dir_relative_path (shared with local run creation) - Verify downloaded files against server-recorded SHA-256 hashes; restore _capsula metadata best-effort from the server's structured data and write a _capsula/pulled.json origin marker - Download into a temporary directory and rename atomically; existing run directories require --force to replace - Restore only relative paths contained in the run directory (syntactic check); full path-safety hardening follows the ResolvedProjectPath work (#1098, #1146) - Encode URL file paths segment-wise with NON_ALPHANUMERIC (allowlist) so arbitrary filenames round-trip without a curated character list
shunsuke-shimomura
added a commit
that referenced
this pull request
Sep 8, 2026
Add a pull command that downloads a run from a Capsula server and restores it under the local vault, as the counterpart of capsula push (#1177): - Extend GET /api/v1/runs/{id} with a files array (path, size, hash); the server-internal storage_path is not exposed - Reconstruct the run directory deterministically from the run's ULID and name via the new capsula_core::run::run_dir_relative_path (shared with local run creation) - Verify downloaded files against server-recorded SHA-256 hashes; restore _capsula metadata best-effort from the server's structured data and write a _capsula/pulled.json origin marker - Download into a temporary directory and rename atomically; existing run directories require --force to replace - Restore only relative paths contained in the run directory (syntactic check); full path-safety hardening follows the ResolvedProjectPath work (#1098, #1146) - Encode URL file paths segment-wise with NON_ALPHANUMERIC (allowlist) so arbitrary filenames round-trip without a curated character list
shunsuke-shimomura
added a commit
that referenced
this pull request
Sep 8, 2026
Add a pull command that downloads a run from a Capsula server and restores it under the local vault, as the counterpart of capsula push (#1177): - Extend GET /api/v1/runs/{id} with a files array (path, size, hash); the server-internal storage_path is not exposed - Reconstruct the run directory deterministically from the run's ULID and name via the new capsula_core::run::run_dir_relative_path (shared with local run creation) - Verify downloaded files against server-recorded SHA-256 hashes; restore _capsula metadata best-effort from the server's structured data and write a _capsula/pulled.json origin marker - Download into a temporary directory and rename atomically; existing run directories require --force to replace - Restore only relative paths contained in the run directory (syntactic check); full path-safety hardening follows the ResolvedProjectPath work (#1098, #1146) - Encode URL file paths segment-wise with NON_ALPHANUMERIC (allowlist) so arbitrary filenames round-trip without a curated character list
shunsuke-shimomura
added a commit
that referenced
this pull request
Sep 9, 2026
Add a pull command that downloads a run from a Capsula server and restores it under the local vault, as the counterpart of capsula push (#1177): - Extend GET /api/v1/runs/{id} with a files array (path, size, hash); the server-internal storage_path is not exposed - Reconstruct the run directory deterministically from the run's ULID and name via the new capsula_core::run::run_dir_relative_path (shared with local run creation) - Verify downloaded files against server-recorded SHA-256 hashes; restore _capsula metadata best-effort from the server's structured data and write a _capsula/pulled.json origin marker - Download into a temporary directory and rename atomically; existing run directories require --force to replace - Restore only relative paths contained in the run directory (syntactic check); full path-safety hardening follows the ResolvedProjectPath work (#1098, #1146) - Encode URL file paths segment-wise with NON_ALPHANUMERIC (allowlist) so arbitrary filenames round-trip without a curated character list
shunsuke-shimomura
added a commit
that referenced
this pull request
Sep 9, 2026
* feat: add capsula pull command Add a pull command that downloads a run from a Capsula server and restores it under the local vault, as the counterpart of capsula push (#1177): - Extend GET /api/v1/runs/{id} with a files array (path, size, hash); the server-internal storage_path is not exposed - Reconstruct the run directory deterministically from the run's ULID and name via the new capsula_core::run::run_dir_relative_path (shared with local run creation) - Verify downloaded files against server-recorded SHA-256 hashes; restore _capsula metadata best-effort from the server's structured data and write a _capsula/pulled.json origin marker - Download into a temporary directory and rename atomically; existing run directories require --force to replace - Restore only relative paths contained in the run directory (syntactic check); full path-safety hardening follows the ResolvedProjectPath work (#1098, #1146) - Encode URL file paths segment-wise with NON_ALPHANUMERIC (allowlist) so arbitrary filenames round-trip without a curated character list * fix: address PR #1178 review findings (F1-F4, F6-F10, F13-F17) Merge blockers: - F1/F3/F6: --force now only replaces runs carrying the _capsula/pulled.json marker; locally produced runs are never replaced and the already-exists errors distinguish the two cases. push (and push --all) refuses/skips pulled runs so lossy reconstructions cannot degrade the server's copy. The existence check is re-done at replacement time, so a directory appearing during the download is no longer clobbered. - F2: the download temp directory now lives directly under the vault root (same filesystem, atomic rename) instead of vault/<date>/, so an interrupted pull cannot leave a phantom run at the depth the vault scanners walk. Non-blockers taken along: - F4 (minimum): non-ULID pull arguments fail fast with a specific error - F7/F8: run name and vault name are validated as single path components before being joined into paths - F9: reuse capsula_core::util::hex_encode instead of local copies - F10: rename the pull-side sanitizer to checked_run_relative_path to stop sharing a name with the server's normalizing variant - F13: percent-encoding no longer escapes RFC 3986 unreserved chars - F14: shared fetch_run_files used by both run-detail handlers - F15: verify downloaded sizes; warn on negative duration_ms; align duration_ms width with the server model - F16: document the round-trip fidelity gaps in the CLI reference - F17: regression tests for all of the above (16 integration tests) * fix: address PR #1178 review comments Pull runs of a non-configured vault into the default vault location. The configured `[vault] path` describes the configured vault only, so restoring another vault's run next to it placed the run in a directory that was never chosen for it (an external directory, for instance). The default `.capsula/<name>` layout only existed as an inline format string inside `VaultConfig`'s Deserialize impl, which is why `pull` could not ask for it. Extract it as `DEFAULT_VAULT_ROOT` plus `default_vault_path()` in capsula-config and use it from both the config default and `pull`. A run of another vault now defaults to `.capsula/<vault>/` under the project root. An explicit `--vault-path` / `CAPSULA_VAULT_PATH` override still wins, so `resolve_vault_path()` reports its source through `VaultPathSource` and `LoadedConfig` carries it. The decision lives in `resolve_pull_vault_dir()` so it is unit-testable. Also centralize the pulled-run check: `is_pulled_run()` is now public and replaces the open-coded `pulled.json` checks in `push_single_run()` and in the `push --all` skip.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
capture-fileglob patterns*and**semantics and literal Unix backslashesCloses #1067.
This PR is stacked on #1098, which provides
ResolvedProjectPath.Testing
just lintjust testAI assistance
Breaking changes
breaking changelabel is appliedAbsolute, parent-relative, and symlink-based capture patterns that previously worked are now rejected or not traversed.
This is part 3 of 4 in a stack made with GitButler:
capture-file: preserve artifact integrity #1147capture-file: constrain globs to the project root #1146 👈