Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions docs/NATIVE_ONLY_REDESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,10 @@ Deliverables:

- The integration is unverified against a notarized build with
associated-domain entitlements wired (the macOS build cannot be
exercised from CI on Linux). A follow-up validation pass on a real
macOS host is required before declaring Phase 3 complete.
exercised from CI on Linux). Run
`scripts/validate-phase3-hardware.sh` on a real macOS host and attach a
completed `docs/phase3-hardware-validation-report.md` before declaring
Phase 3 complete.
- Domain expansion beyond `example.com` is tracked in issue #8.

### Phase 4: command migration and deprecation
Expand Down
62 changes: 62 additions & 0 deletions docs/PHASE3_HARDWARE_VALIDATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Phase 3 notarized hardware validation

Issue: #43

Phase 3 is not complete until APW.app has been exercised on real macOS
hardware as a Developer ID signed, notarized, stapled bundle with associated
domain entitlements. CI can build and unit test the broker, but it cannot prove
that Apple's credential picker appears for a notarized app on a user's machine.

## Validation command

Run this on the real validation host:

```bash
./scripts/validate-phase3-hardware.sh \
--app /path/to/APW.app \
--apw /path/to/apw \
--url https://example.com \
--unsupported-url https://unsupported.invalid \
--report docs/phase3-hardware-validation-report.md
```

Use a test associated domain that has a valid AASA file and an iCloud Keychain
credential already saved for that domain. The script intentionally does not
persist returned usernames or passwords.

## What the script proves

The script fails closed unless all of these checks pass:

- host is macOS
- `APW.app` exists and contains `Contents/MacOS/APW`
- the app bundle passes `codesign --deep --strict --verify`
- the app bundle passes `spctl --assess --type execute`
- the app bundle passes `xcrun stapler validate`
- bundle entitlements include at least one `webcredentials:` associated domain
- `apw app install` succeeds
- `apw app launch` succeeds
- `apw status --json` reports the app installed and the broker running
- `apw login <url>` exits successfully
- the operator confirms the native iCloud Keychain picker appeared
- the operator confirms the selected credential was returned by APW
- the operator records cancel, denied, and timeout observations
- an unsupported-domain credential request fails with a domain/no-credential
error

The operator confirmations are required because the picker is a user-mediated
OS UI flow and the script must not scrape or save credential values.

## Error paths to record

During a successful run, the script requires observations for the documented
error paths before it writes the generated report:

- cancel: dismiss the credential picker and record the broker error code
- denied: deny the APW approval prompt, when that prompt is present
- timeout: stop or block the broker and record the CLI timeout code
- unsupported domain: request a domain outside the app entitlement set
(automated by `--unsupported-url`)

Do not remove the Phase 3 exit blocker in `docs/NATIVE_ONLY_REDESIGN.md` until
the report captures success plus the required error paths on a notarized host.
8 changes: 8 additions & 0 deletions docs/SECURITY_POSTURE_AND_TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ cargo test --manifest-path rust/Cargo.toml --test native_app_e2e
./scripts/verify-universal-binaries.sh
```

Before claiming Phase 3 complete for a public release, run the real-hardware
notarized broker validation in
[PHASE3_HARDWARE_VALIDATION.md](PHASE3_HARDWARE_VALIDATION.md). This check is
manual because CI cannot prove that the native iCloud Keychain picker appears
for a notarized app with associated-domain entitlements.

## Security-focused regression coverage

The Rust test suite covers:
Expand All @@ -109,6 +115,8 @@ The Rust test suite covers:
- native app diagnostics and `APW_DEMO=1` bootstrap credential file initialization
- end-to-end v2 app install, launch, status, doctor, and login flows
- direct-exec fallback, unsupported-domain handling, denial handling, and malformed broker response mapping
- a manual notarized-hardware validation contract for the Phase 3
AuthenticationServices broker flow
- diagnostic-bundle layout, archive permissions, and fail-closed redaction
when a plausible credential pattern would otherwise reach the bundle
- external fallback provider path hardening, including relative paths, `~`, world-writable
Expand Down
49 changes: 49 additions & 0 deletions docs/phase3-hardware-validation-report.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Phase 3 hardware validation report

Issue: #43

Status: not yet validated

## Host

- Date:
- macOS version:
- Hardware model:
- Architecture:
- APW.app version:
- APW CLI version:
- Test associated domain:
- Unsupported-domain test URL:
- Release tag or commit:

## Automated checks

- [ ] `codesign --deep --strict --verify APW.app`
- [ ] `spctl --assess --type execute --verbose APW.app`
- [ ] `xcrun stapler validate APW.app`
- [ ] Associated-domain entitlement contains `webcredentials:`
- [ ] `apw app install`
- [ ] `apw app launch`
- [ ] `apw status --json` reports installed app and running broker
- [ ] `apw login <url>` exits successfully

## Operator-observed flow

- [ ] Native iCloud Keychain credential picker appeared
- [ ] Operator selected the expected test credential
- [ ] APW returned a credential response without saving it to disk

## Error paths

| Path | Expected result | Observed result |
| --- | --- | --- |
| Success | credential response with `userMediated: true` | |
| Cancel | stable canceled/denied broker error | |
| Denied | stable denied broker error | |
| Timeout | communication timeout error | |
| Unsupported domain | no-results or unsupported-domain error from `--unsupported-url` | |

## Notes

- Do not paste real usernames, passwords, session tokens, or credential payloads
into this report.
Loading
Loading