History

fix(server): treat removed Bitbucket permissions endpoint as unknown, not blocking (#6525)

Lars Nieuwenhuis committed 2 months ago

Commit 75472801 parent afca73d2 files · +58 −1Browse files

Unified · Split

2 files
  1. apps/server/src/pullRequest/BitbucketPullRequestApi.test.ts +40 −0
  2. apps/server/src/pullRequest/BitbucketPullRequestApi.ts +18 −1
apps/server/src/pullRequest/BitbucketPullRequestApi.test.ts+40−0
@@ -867,6 +867,46 @@ layer("BitbucketPullRequestApi.layer", (it) => { · 866 unmodified lines
867 }),867 }),
868 );868 );
869 869
870 it.effect(
871 "reads a removed permissions endpoint as granted rather than failing the merge on it",
872 () =>
873 Effect.gen(function* () {
874 // Bitbucket retired /user/permissions/repositories under CHANGE-2770: every account now
875 // gets HTTP 410 here, whatever it may do.
876 mockedRequest.mockReturnValue(
877 Effect.fail(
878 new BitbucketApi.BitbucketResponseError({
879 operation: "request",
880 status: 410,
881 responseBodyLength: 0,
882 }),
883 ),
884 );
885 const api = yield* BitbucketPullRequestApi.BitbucketPullRequestApi;
886
887 assert.isTrue(yield* api.getRepositoryPermission({ repository: "acme/web" }));
888 }),
889 );
890
891 it.effect("still fails the permission read on a failure that is not the removed endpoint", () =>
892 Effect.gen(function* () {
893 mockedRequest.mockReturnValue(
894 Effect.fail(
895 new BitbucketApi.BitbucketResponseError({
896 operation: "request",
897 status: 401,
898 responseBodyLength: 0,
899 }),
900 ),
901 );
902 const api = yield* BitbucketPullRequestApi.BitbucketPullRequestApi;
903
904 const error = yield* Effect.flip(api.getRepositoryPermission({ repository: "acme/web" }));
905
906 assert.strictEqual(error._tag, "BitbucketResponseError");
907 }),
908 );
909
870 it.effect("reads the workspace's people and marks whoever is already a reviewer", () =>910 it.effect("reads the workspace's people and marks whoever is already a reviewer", () =>
871 Effect.gen(function* () {911 Effect.gen(function* () {
872 mockedRequest912 mockedRequest
apps/server/src/pullRequest/BitbucketPullRequestApi.ts+18−1
@@ -107,6 +107,16 @@ export type BitbucketPullRequestApiError = · 106 unmodified lines
107 | BitbucketRepositoryUnsupportedError107 | BitbucketRepositoryUnsupportedError
108 | BitbucketDiffCommitError;108 | BitbucketDiffCommitError;
109 109
110/**
111 * `/user/permissions/repositories` answering CHANGE-2770's removal notice rather than a
112 * permission — Bitbucket sends this for every account now, not only ones it would have refused.
113 */
114function isRepositoryPermissionRemovedError(
115 error: BitbucketPullRequestApiError,
116): error is BitbucketApi.BitbucketResponseError {
117 return error._tag === "BitbucketResponseError" && error.status === 410;
118}
119
110/**120/**
111 * Bitbucket's own ceiling. Asking for more does not fail — it answers with an empty page and no121 * Bitbucket's own ceiling. Asking for more does not fail — it answers with an empty page and no
112 * error at all, so this is a number to respect rather than to push against.122 * error at all, so this is a number to respect rather than to push against.
@@ -553,6 +563,13 @@ export const make = Effect.gen(function* () { · 440 unmodified lines
553 // Nothing on the repository, the pull request or the workspace states what the credentials563 // Nothing on the repository, the pull request or the workspace states what the credentials
554 // may do, so this endpoint is the one request Bitbucket makes unavoidable. It is asked564 // may do, so this endpoint is the one request Bitbucket makes unavoidable. It is asked
555 // alongside the reads the detail was already making, so it costs no round trip of its own.565 // alongside the reads the detail was already making, so it costs no round trip of its own.
566 //
567 // Bitbucket permanently removed this endpoint (CHANGE-2770): every account now gets HTTP 410
568 // in place of an answer, whatever it may do. That is the deprecated-endpoint signal, not a
569 // permission being refused, so it is read the same way an unreachable read already is
570 // elsewhere — as a permission that could not be learned, which grants rather than blocks, and
571 // leaves the actual merge or write to say why if the account may not do it. Any other failure
572 // (a bad token, a network fault, an unreadable body) still fails as it did before.
556 getRepositoryPermission: (input) =>573 getRepositoryPermission: (input) =>
557 withRepository(input.repository, () =>574 withRepository(input.repository, () =>
558 readPage({575 readPage({
@@ -562,7 +579,7 @@ export const make = Effect.gen(function* () { · 3 unmodified lines
562 )}`,579 )}`,
563 decode: decodeRepositoryPermissionJson,580 decode: decodeRepositoryPermissionJson,
564 }),581 }),
565 ),582 ).pipe(Effect.catchIf(isRepositoryPermissionRemovedError, () => Effect.succeed(true))),
566 583
567 getPullRequestDiff: (input) =>584 getPullRequestDiff: (input) =>
568 input.commit !== undefined && !isCommitSha(input.commit)585 input.commit !== undefined && !isCommitSha(input.commit)