perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

Align remaining sync missing-repo reads

alice b6b6c2b8 00a4064f

+28 -5
+2 -2
docs/TEST_AUDIT.md
··· 13 13 The current baseline for saying "the audited suite is green" is: 14 14 15 15 - `prove -lr t` 16 - - latest full green result in the realigned Meridian worktree: `Files=61, Tests=3110` 16 + - latest full green result in the realigned Meridian worktree: `Files=61, Tests=3119` 17 17 - `prove -lv t/server-auth.t` 18 18 - `perl -c script/differential-validate` 19 19 - `PERLSKY_RUN_REFERENCE_DIFF=1 prove -lv t/reference-differential.t` ··· 76 76 - `com.atproto.identity.resolveHandle` should treat well-formed but unresolved handles as `400 InvalidRequest` with `Unable to resolve handle`, matching the official runtime instead of returning a local `404 HandleNotFound`. 77 77 - Remote `did:web` DID docs, conservative `resolveIdentity` handle validation, and external handle adoption all need explicit coverage because small resolver-policy drifts turn into visible interop bugs quickly. 78 78 - Remote `did:plc` DID docs should resolve through the PLC directory defaults even when `plc_url` is not explicitly configured; gating that path on local config silently breaks federated identity lookups. 79 - - Missing-repo read paths now match the official runtime more closely: `describeRepo`, `sync.getLatestCommit`, `sync.getHead`, and `sync.getRepoStatus` report `400 RepoNotFound`, while `listRecords` reports `400 InvalidRequest` / `Could not find repo: ...`. 79 + - Missing-repo read paths now match the official runtime more closely: `describeRepo`, `sync.getLatestCommit`, `sync.getRecord`, `sync.getRepo`, `sync.getCheckout`, `sync.getHead`, and `sync.getRepoStatus` report `400 RepoNotFound`, while `listRecords` reports `400 InvalidRequest` / `Could not find repo: ...`. 80 80 - `com.atproto.repo.getRecord` must honor `cid` when present, and `putRecord` / `deleteRecord` must actually enforce `swapRecord`; those negative edges are now covered directly. 81 81 - `com.atproto.repo.createRecord` follows the reference runtime by ignoring a stray `swapRecord` field, and direct reference coverage now pins `putRecord` / `deleteRecord` `swapCommit` and `swapRecord` mismatch semantics explicitly. 82 82 - App-password sessions follow the official runtime more closely than the older local assumptions did: access-token scopes use the `com.atproto.appPass` / `com.atproto.appPassPrivileged` names, standard app-password sessions may list app passwords, privileged-only `getServiceAuth` failures report `InvalidRequest`, and revoked refresh tokens on `refreshSession` fail with `400 ExpiredToken`.
+3 -3
lib/ATProto/PDS/API/Sync.pm
··· 71 71 }); 72 72 73 73 $registry->register('com.atproto.sync.getRepo', sub ($c, $endpoint) { 74 - my $account = _readable_repo_by_did($c); 74 + my $account = _readable_repo_by_did($c, missing_status => 400); 75 75 return _render_repo_car($c, $account->{did}); 76 76 }); 77 77 78 78 $registry->register('com.atproto.sync.getCheckout', sub ($c, $endpoint) { 79 - my $account = _readable_repo_by_did($c); 79 + my $account = _readable_repo_by_did($c, missing_status => 400); 80 80 return _render_repo_car($c, $account->{did}); 81 81 }); 82 82 83 83 $registry->register('com.atproto.sync.getRecord', sub ($c, $endpoint) { 84 - my $account = _readable_repo_by_did($c); 84 + my $account = _readable_repo_by_did($c, missing_status => 400); 85 85 return _render_car( 86 86 $c, 87 87 _record_proof_car(
+11
script/differential-validate
··· 1887 1887 latest_commit => normalize_xrpc_error(get_form($server{$name}{origin}, 'com.atproto.sync.getLatestCommit', { 1888 1888 did => $missing_did, 1889 1889 })), 1890 + sync_record => normalize_xrpc_error(get_form($server{$name}{origin}, 'com.atproto.sync.getRecord', { 1891 + did => $missing_did, 1892 + collection => 'app.bsky.feed.post', 1893 + rkey => 'diffpost', 1894 + })), 1895 + repo_export => normalize_xrpc_error(get_form($server{$name}{origin}, 'com.atproto.sync.getRepo', { 1896 + did => $missing_did, 1897 + })), 1898 + checkout_export => normalize_xrpc_error(get_form($server{$name}{origin}, 'com.atproto.sync.getCheckout', { 1899 + did => $missing_did, 1900 + })), 1890 1901 head => normalize_xrpc_error(get_form($server{$name}{origin}, 'com.atproto.sync.getHead', { 1891 1902 did => $missing_did, 1892 1903 })),
+12
t/repo-api.t
··· 377 377 'sync.getRecord proof includes the current record block', 378 378 ); 379 379 380 + $t->get_ok('/xrpc/com.atproto.sync.getRecord?did=did:web:missing.test&collection=app.bsky.feed.post&rkey=first-post') 381 + ->status_is(400) 382 + ->json_is('/error' => 'RepoNotFound'); 383 + 380 384 $t->get_ok("/xrpc/com.atproto.sync.getRepoStatus?did=$did") 381 385 ->status_is(200) 382 386 ->json_is('/did' => $did) ··· 397 401 ->content_type_like(qr{application/vnd\.ipld\.car}) 398 402 ->content_like(qr/.+/s); 399 403 404 + $t->get_ok('/xrpc/com.atproto.sync.getRepo?did=did:web:missing.test') 405 + ->status_is(400) 406 + ->json_is('/error' => 'RepoNotFound'); 407 + 400 408 $t->get_ok("/xrpc/com.atproto.sync.getCheckout?did=$did") 401 409 ->status_is(200) 402 410 ->content_type_like(qr{application/vnd\.ipld\.car}) 403 411 ->content_like(qr/.+/s); 412 + 413 + $t->get_ok('/xrpc/com.atproto.sync.getCheckout?did=did:web:missing.test') 414 + ->status_is(400) 415 + ->json_is('/error' => 'RepoNotFound'); 404 416 405 417 $t->get_ok("/xrpc/com.atproto.sync.getHead?did=$did") 406 418 ->status_is(200)