Add project-root-aware path type - #1098
Draft
shunichironomura wants to merge 5 commits into
Draft
shunichironomura wants to merge 5 commits into
shunichironomura wants to merge 5 commits into
Conversation
1 of 2 tasks
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## hook-outcome-fail-closed #1098 +/- ##
============================================================
+ Coverage 53.57% 54.61% +1.03%
============================================================
Files 41 42 +1
Lines 4166 4283 +117
============================================================
+ Hits 2232 2339 +107
- Misses 1934 1944 +10 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
shunichironomura
marked this pull request as draft
July 7, 2026 12:57
shunichironomura
force-pushed
the
project-relative-path
branch
2 times, most recently
from
July 7, 2026 13:15
5ef29d9 to
f3ebdfc
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 7, 2026 14:24
93a5223 to
085d153
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 7, 2026 14:24
f3ebdfc to
eb92bb7
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 20, 2026 23:09
085d153 to
52aeb41
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 20, 2026 23:09
eb92bb7 to
920579c
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 22, 2026 06:29
52aeb41 to
46ef647
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
2 times, most recently
from
July 22, 2026 06:44
5a73c17 to
276c96e
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 22, 2026 06:49
e36bd14 to
6a82a85
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 22, 2026 06:49
276c96e to
76650da
Compare
This was referenced Jul 22, 2026
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 22, 2026 10:42
6a82a85 to
985d14e
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 22, 2026 10:42
76650da to
242cc6c
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
July 22, 2026 22:53
985d14e to
7d291d9
Compare
shunichironomura
force-pushed
the
project-relative-path
branch
from
July 22, 2026 22:53
242cc6c to
0806b44
Compare
1 of 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.
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
3 times, most recently
from
September 17, 2026 00:08
709e249 to
0d7ac32
Compare
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
October 1, 2026 07:49
0d7ac32 to
8ed6f9f
Compare
shunichironomura
added this pull request to stack #1271
October 1, 2026 07:53
shunichironomura
force-pushed
the
hook-outcome-fail-closed
branch
from
October 1, 2026 08:24
8ed6f9f to
6833c58
Compare
shunichironomura
removed this pull request from stack #1271
October 1, 2026 08:24
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
Testing
Closes #575
This is part 2 of 4 in a stack made with GitButler:
capture-file: preserve artifact integrity #1147capture-file: constrain globs to the project root #1146