Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
4ce3108
fix(auth): classify unauthenticated requests explicitly
ElmanCod110 Oct 27, 2026
42f4ec1
feat(auth): add a typed authentication-required exception
ElmanCod110 Oct 27, 2026
0ef4ad3
fix(api): guard config and service initialization failures
ElmanCod110 Oct 27, 2026
a228508
test(api): cover safe initialization failures and auth status
ElmanCod110 Oct 27, 2026
6c9f38f
fix(api): close initialization boundary around dispatch
ElmanCod110 Oct 27, 2026
0d4c0ba
feat(archive): add a typed archive-input failure
ElmanCod110 Oct 27, 2026
093a48f
feat(archive): classify stale extraction steps
ElmanCod110 Oct 27, 2026
f73ebf5
feat(storage): classify unavailable archive jobs
ElmanCod110 Oct 27, 2026
054d86c
feat(package): classify unavailable package records
ElmanCod110 Oct 27, 2026
2848b1a
feat(package): classify rejected package restores
ElmanCod110 Oct 27, 2026
16345b2
fix(package): distinguish unavailable records from storage faults
ElmanCod110 Oct 27, 2026
acb2d49
fix(storage): classify missing and non-owned jobs
ElmanCod110 Oct 27, 2026
bf6cc2e
fix(archive): type unsafe archive path failures
ElmanCod110 Oct 27, 2026
9ef3473
fix(archive): separate malformed archives from storage failures
ElmanCod110 Oct 27, 2026
4a3d37f
fix(crypto): separate restore rejection from storage faults
ElmanCod110 Oct 27, 2026
5bd696e
fix(crypto): classify malformed V14 package metadata
ElmanCod110 Oct 27, 2026
a1e8397
fix(api): preserve typed errors and verify failure cleanup
ElmanCod110 Oct 27, 2026
0a82a39
fix(archive): classify corrupt streams and size limits as input failures
ElmanCod110 Oct 27, 2026
e160b13
fix(archive): surface rollback and staging cleanup failures
ElmanCod110 Oct 27, 2026
7f403db
test(api): cover typed missing resources and storage failure privacy
ElmanCod110 Oct 27, 2026
8913799
test(package): assert typed unavailable-package semantics
ElmanCod110 Oct 27, 2026
4bb5ea1
test(package): verify cleanup helpers and plaintext preservation
ElmanCod110 Oct 27, 2026
1319f9e
test(restore): verify centralized plaintext cleanup contract
ElmanCod110 Oct 27, 2026
d1d637b
fix(archive): classify rejected packages and verify extraction cleanup
ElmanCod110 Oct 27, 2026
6e69ba8
refactor(archive): make trusted and untrusted path policy explicit
ElmanCod110 Oct 27, 2026
133773d
test(archive): cover corrupt ZIPs, traversal, and destination preserv…
ElmanCod110 Oct 27, 2026
5e1ece6
build(deps): commit Composer-generated dependency lock
ElmanCod110 Oct 27, 2026
1dfc7ff
docs(api): update error contract after typed failure separation
ElmanCod110 Oct 27, 2026
f52f96d
docs(release): reconcile QA matrix with candidate evidence
ElmanCod110 Oct 27, 2026
8c2e611
fix(crypto): classify AEAD authentication failures
ElmanCod110 Oct 27, 2026
eb78771
feat(crypto): add typed V14 authentication rejection
ElmanCod110 Oct 27, 2026
ffd85e4
feat(crypto): add typed V14 stream rejection
ElmanCod110 Oct 27, 2026
5a1c347
fix(crypto): classify V14 stream rejection and storage errors
ElmanCod110 Oct 27, 2026
b7c17c7
fix(crypto): preserve no-overwrite publication and verify stream cleanup
ElmanCod110 Oct 27, 2026
9b73cf9
docs(release): state explicitly that QA plan is not manual evidence
ElmanCod110 Oct 27, 2026
b5ac996
fix(crypto): verify stream inputs and secure temp output permissions
ElmanCod110 Oct 27, 2026
68f6d11
fix(crypto): inherit protected mode from atomic stream publication
ElmanCod110 Oct 27, 2026
29f6b57
fix(storage): verify upload cleanup and expire state under lock
ElmanCod110 Oct 27, 2026
4bf4f38
test(storage): verify direct cleanup and nested symlink safety
ElmanCod110 Oct 27, 2026
5809326
fix(package): fail closed on corrupt catalog listings
ElmanCod110 Oct 27, 2026
5883418
test(package): cover catalog listing integrity and symlink rejection
ElmanCod110 Oct 27, 2026
7df4a33
docs(api): record strict catalog and upload cleanup contracts
ElmanCod110 Oct 27, 2026
babd25f
docs(release): add catalog and upload cleanup regression gates
ElmanCod110 Oct 27, 2026
0dc2d9f
fix(audit): normalize self path on Windows
ElmanCod110 Oct 27, 2026
9b0d8f7
fix(release): verify signer inputs and written artifacts
ElmanCod110 Oct 27, 2026
0800113
fix(storage): report root and orphan-symlink cleanup failures
ElmanCod110 Oct 27, 2026
17405c7
fix(restore): verify owned output identity during rollback
ElmanCod110 Oct 27, 2026
f7a8339
fix(storage): verify controller cleanup ownership and deletion
ElmanCod110 Oct 27, 2026
ed949ce
test(storage): verify controller cleanup and nested symlink safety
ElmanCod110 Oct 27, 2026
2d7f993
fix(archive): verify atomic ZIP publication and owned cleanup
ElmanCod110 Oct 27, 2026
e620bee
fix(archive): capture ZIP inode after archive finalization
ElmanCod110 Oct 27, 2026
a2cf1ad
fix(archive): verify cleanup after destination identity failure
ElmanCod110 Oct 27, 2026
9942a79
fix(restore): surface destination identity cleanup failures
ElmanCod110 Oct 27, 2026
0111a4d
fix(ci): block lockfile PR creation when dependency audit fails
ElmanCod110 Oct 27, 2026
d795045
docs(changelog): record v1.0.0 readiness and security hardening
ElmanCod110 Oct 27, 2026
eb7286e
docs(release): clarify candidate lockfile and remaining release gates
ElmanCod110 Oct 27, 2026
0a8b385
fix(security): verify token storage identity and fail on cleanup errors
ElmanCod110 Oct 27, 2026
af5cf5f
test(security): cover package-scoped token revocation and corrupt rec…
ElmanCod110 Oct 27, 2026
9871bc1
fix(security): avoid deleting token paths without ownership proof
ElmanCod110 Oct 27, 2026
9e5baae
fix(package): verify catalog record and lock identities
ElmanCod110 Oct 27, 2026
57b6dec
test(package): cover owner-checked catalog deletion
ElmanCod110 Oct 27, 2026
9c7bd17
fix(storage): harden job state writes and owned directory cleanup
ElmanCod110 Oct 27, 2026
affd77b
fix(storage): correct job store declaration and preserve storage errors
ElmanCod110 Oct 27, 2026
de4a781
test(storage): cover job state integrity and symlink-safe cleanup
ElmanCod110 Oct 27, 2026
f68871f
test(storage): import the typed job-unavailable exception correctly
ElmanCod110 Oct 27, 2026
9fc18c0
test(archive): assert typed failure during rollback
ElmanCod110 Oct 27, 2026
81441fb
test(archive): assert typed depth-limit rejection
ElmanCod110 Oct 27, 2026
2c3e336
test(archive): assert typed policy rejection
ElmanCod110 Oct 27, 2026
0251a6a
test(crypto): cover typed restore failures and existing outputs
ElmanCod110 Oct 27, 2026
35f1f9b
test(release): include locked dependencies in signer fixture
ElmanCod110 Oct 27, 2026
f139da7
test(crypto): prevent false-positive existing-destination assertion
ElmanCod110 Oct 27, 2026
b967f55
ci(windows): add package and release integrity smoke coverage
ElmanCod110 Oct 27, 2026
09639af
ci(security): require release lockfile and run full regression suite
ElmanCod110 Oct 27, 2026
c69f1b7
docs(release): record Windows smoke and stable-format CI gates
ElmanCod110 Oct 27, 2026
b74fda6
docs(security): explain metadata leakage and offline guessing
ElmanCod110 Oct 27, 2026
d93f563
docs(security): document offline guessing and metadata leakage
ElmanCod110 Oct 27, 2026
812455c
docs(migration): define stable format compatibility policy
ElmanCod110 Oct 27, 2026
911914f
docs(format): specify visible metadata and offline attack limits
ElmanCod110 Oct 27, 2026
887f3c4
docs(migration): make legacy reader support policy explicit
ElmanCod110 Oct 27, 2026
600e732
docs(changelog): record release gates and security guidance
ElmanCod110 Oct 27, 2026
a305183
docs(release): add stable KDF resource-budget gate
ElmanCod110 Oct 27, 2026
894f2cb
test: strengthen package catalog privacy regressions
ElmanCod110 Oct 27, 2026
4a9853c
test: assert server package format diagnostics
ElmanCod110 Oct 27, 2026
14de591
test: verify version metadata policy consistency
ElmanCod110 Oct 27, 2026
5711e78
test: verify runtime version derives from VERSION
ElmanCod110 Oct 27, 2026
7df5584
fix: expose server package format in diagnostics
ElmanCod110 Oct 27, 2026
9e337a9
docs: record catalog privacy and diagnostics coverage
ElmanCod110 Oct 27, 2026
a387c20
fix: verify cleanup of incomplete V14 package builds
ElmanCod110 Oct 27, 2026
51fde33
test: cover failed V14 service build cleanup
ElmanCod110 Oct 27, 2026
9be19cf
docs: record V14 failed-build cleanup regression
ElmanCod110 Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,57 @@ jobs:
}
- name: Validate SPK13 icon integration safeguards
run: php tests/WindowsSpk13IconIntegrationTest.php

windows-smoke:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: sodium,zip,pdo_mysql,mbstring,intl,dom,xml
coverage: none
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Validate and install locked Composer dependencies
shell: pwsh
run: |
composer validate --strict --no-check-publish
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
composer install --no-interaction --prefer-dist
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
composer audit --no-interaction
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: PHP syntax check
shell: pwsh
run: |
Get-ChildItem app,bin,public,tests -Recurse -File -Filter *.php | ForEach-Object {
php -l $_.FullName
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
- name: Runtime self-check and source audit
shell: pwsh
run: |
php bin/self-check.php
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
php bin/source-audit.php
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: V14 package round-trip and restore safety
shell: pwsh
run: |
php tests/V14PackageRoundTripTest.php
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
php tests/V14RestoreSafetyTest.php
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
php tests/V14PackageArchiveTest.php
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Browser V13 automated round-trip
shell: pwsh
run: node tests/BrowserV13RoundTripTest.mjs
- name: Release signer external trust-root test
shell: pwsh
run: php tests/ReleaseSignerExternalTrustTest.php
8 changes: 7 additions & 1 deletion .github/workflows/refresh-composer-lock.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ jobs:
continue-on-error: true
run: composer audit --no-interaction

- name: Fail the workflow when dependency audit fails
if: steps.audit.outcome == 'failure'
run: |
echo "::error::composer audit failed. Review and resolve or document dependency findings before merging."
exit 1

- name: Open a pull request with the generated lockfile
uses: peter-evans/create-pull-request@v7
with:
Expand All @@ -45,7 +51,7 @@ jobs:
## Summary
- Generate `composer.lock` using Composer in a clean GitHub Actions runner.
- Validate the manifest and lockfile with `composer validate --strict --no-check-publish`.
- Run `composer audit --no-interaction`; inspect the workflow result before merging.
- Run `composer audit --no-interaction`; this workflow fails before opening a PR if the audit step fails (including an audit command marked continue-on-error for outcome reporting).

## Review checklist
- [ ] Confirm the lockfile was generated by Composer (not hand-written).
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ jobs:
run: |
find app bin public tests -type f -name '*.php' -print0 | xargs -0 -n1 php -l

- name: Require Composer lockfile for release-readiness branches
if: github.head_ref == 'release/v1.0.0-readiness' || github.base_ref == 'release/v1.0.0-readiness' || startsWith(github.head_ref, 'work/v1.0.0-reconciliation-') || startsWith(github.ref_name, 'work/v1.0.0-reconciliation-')
run: |
if [ ! -f composer.lock ]; then
echo "::error::A Composer-generated composer.lock is required for release-readiness changes."
exit 1
fi

- name: Composer manifest validation
run: composer validate --no-check-publish

Expand Down Expand Up @@ -92,5 +100,8 @@ jobs:
- name: Source security audit
run: php bin/source-audit.php

- name: Full regression and security suite
run: php bin/security-test.php --full

- name: Legacy browser V13 round-trip
run: node tests/BrowserV13RoundTripTest.mjs
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
# Changelog

## Unreleased — MVP readiness and repository maintenance
## Unreleased — v1.0.0 readiness, API reliability, and storage hardening

- Put API configuration loading and service initialization inside the generic error boundary; typed authentication failures now return HTTP 401, and missing resources are separated from storage/programming failures.
- Added typed archive-step conflicts, rejected archive/package input, and storage faults so malformed input can return a documented 4xx while I/O failures remain generic 500 responses.
- Hardened restore rollback, controller path cleanup, portable archive publication, and resumable-upload deletion with ownership checks, no-overwrite publication, post-cleanup verification, and surfaced cleanup errors.
- Verified cleanup of incomplete V14 package builds and added a regression ensuring a failed build leaves no encrypted-package artifacts behind.
- Made catalog listings fail closed on malformed JSON, invalid records, and symlinked records instead of silently presenting an incomplete inventory.
- Ensured missing and unauthorized package lookups use the same privacy-preserving catalog response, and exposed the legacy server package format explicitly in runtime diagnostics.
- Added regression coverage for runtime version metadata consistency and the diagnostics package-format contract.
- Added HTTP regressions for configuration failure privacy, method Allow headers, authentication, missing job/package privacy, catalog failure, and restore storage failure.
- Added regressions for corrupt ZIPs, archive traversal, existing-output preservation, catalog listing integrity, controller cleanup, and resumable-upload symlink safety.
- Separated V14 authentication/stream rejection from storage errors while preserving atomic link-based no-replace publication; temporary file identities and restrictive modes are checked before publication.
- Added the Composer-generated lockfile to the release-readiness work branch and made the manual lock refresh workflow fail before creating a PR when dependency audit fails.
- Ported the Windows source-audit self-path normalization and strengthened release-signing input/write verification.
- Reconciled the API error contract and reproducible QA matrix; manual Windows/XAMPP, real-browser, independently trusted signed-artifact, and independent security-review gates remain NOT RUN.
- Kept the stable binary package format isolated in PR #38; it is not the default production writer and is not yet approved for v1.0.0.
- Added a Windows CI smoke job for locked Composer install/audit, PHP syntax, self-check, source audit, V14 restore/archive safety, browser V13 compatibility, and external-trust-root signer verification.
- Added a release-readiness lockfile gate and full regression/security suite to the Security and Release Integrity workflow.
- Fixed a false-positive restore-safety test so an existing destination is accepted as rejected only when the expected typed storage exception is thrown, and verified its content remains unchanged.
- Documented V14/stable-format metadata leakage, offline password-and-pattern guessing, sender-authenticity limits, and the explicit legacy-reader/migration policy.

- Add an executable release-signing regression that verifies Ed25519 signatures against an independently pinned external trust root.
- Fail closed when the audit hash-chain head is missing or corrupt, verify chain integrity before appending, and redact sensitive audit context keys by normalized fragments.
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ After a real root `composer.lock` has been generated with Composer and committed

Before a release, work through the [reproducible release QA matrix](docs/RELEASE-QA.md). It separates CI evidence from manual Windows/XAMPP and real-browser checks; manual scenarios must remain NOT RUN until tested.

## Security limitations and exposed metadata

Encryption does not hide every property of a V14 package. The readable package header/completion records expose the format and generation identifiers, random package ID, creation time, cryptographic/KDF profile, whether a recovery slot exists, and integrity-binding values. ZIP entry structure and encrypted blob lengths can reveal the approximate number and sizes of files and the total package size. The encrypted manifest protects filenames and directory relationships; it does not make the entire package indistinguishable from random data of a fixed size.

A copied package can be attacked offline: an attacker can test password-and-pattern guesses against the wrapped key slot without contacting the application. Argon2id raises the cost of each guess but cannot prevent offline guessing. Use a long, unique password and a separate, non-reused pattern. Web rate limits do not protect a package after an attacker obtains a copy. A lost password/pattern or lost recovery key cannot be recovered by the project.

Package encryption also does not prove who sent a package. Use HTTPS, SFTP, or another trusted transfer channel; when sender identity or artifact substitution matters, verify a checksum or signature through an independently trusted channel. Do not rely on a public key embedded only inside the release artifact as the sole trust root.

The version-independent single-file binary format is still a separately reviewed candidate. Until it is approved and integrated, V14 remains the active server writer and browser V13 remains a separate compatibility format. Do not assume that a legacy package has been converted merely because the application version changes.

## Security philosophy

The application treats cryptography, parsing, filesystem handling, authentication, resource limits, and supply-chain integrity as one security boundary. A stronger cipher alone does not make the system secure; every step between untrusted input and plaintext restore must fail closed.
Expand Down
Loading
Loading