Dashboard › publish › Distillation
3ad737fd-c9fb-41e0-9fb5-f11822fe0506["lore_tm_v1_3IE6AOfSJiau06RLhDgwXiV0lq3KY-rzqV1L8-0jxGs","lore_tm_v1_q2-EBWXNHjQoKwJDa_VKtg-VrMBldHY-LHjBvfP_n9I","lore_tm_v1__RJYlSElmLz9z1lXsWGJeKcHkQMi4erWui7t3UhC5y8","lore_tm_v1_bGW2EqsnhcIa1Q8TcjHKbFDuopAeppf1WlfOA02Ohxk","lore_tm_v1_NN9oar0x_8m8vE3FIQ6vjj3ehKbcOkGXjFpFvAy2bMc"]
Authorization: Bearer <YOUR-TOKEN>, Accept: application/vnd.github+json, and X-GitHub-Api-Version: 2026-03-10; the provided curl examples omit these standard headers.GET /user returns the authenticated user. OAuth app tokens and personal access tokens (classic) require read:user or broader user scope for the private response; otherwise they receive the public response. Private-only required fields include private_gists, total_private_repos, owned_private_repos, disk_usage, collaborators, and two_factor_authentication. Statuses documented: 200, 304, 401, and 403.PATCH /user updates authenticated-user fields name, email, blog, twitter_username, company, location, hireable, and bio; private-email settings remain enforced even when an email parameter is supplied. Statuses documented: 200, 304, 401, 403, 404, and 422.GET /user/{account_id} retrieves public account information by durable numeric user ID rather than mutable login. Enterprise Managed Users and relevant GitHub App bots return 404 unless authenticated as a user or GitHub App with organization access.GET /users lists personal and organization accounts in signup order. Pagination is exclusively via since; per_page defaults to 30 and has a maximum of 100, and the Link header supplies the next-page URL.GET /users/{username} returns public account information. For private profiles, followers and following are 0 unless authenticated as that user; authenticating as that user returns actual values even without OAuth scopes.{/privacy} in a user response’s events_url URI template with /public to retrieve only public events. Omitting it retrieves public events and, when authenticated as that user, private events.GET /users/{username}/hovercard provides contextual user information. Optional paired parameters are subject_type—one of organization, repository, issue, or pull_request—and subject_id; each is required when the other is used. OAuth app tokens and classic personal access tokens need repo scope. Statuses documented: 200, 404, and 422.Authorization header for REST or GraphQL requests; requests are attributed to the app, require the installation’s repository access and app permissions, and are also called “server-to-server” requests. Installation access tokens expire after 1 hour.Contents repository permission. User directed: replace TOKEN with the installation access token in git clone https://x-access-token:TOKEN@github.com/owner/repo.git.GET /users/{username}/installation, GET /repos/{owner}/{repo}/installation, GET /orgs/{org}/installation, or GET /app/installations. 3. Send POST /app/installations/INSTALLATION_ID/access_tokens with the JWT.INSTALLATION_ID in /app/installations/INSTALLATION_ID/access_tokens with the ID of the installation to authenticate as.INSTALLATION_ID with the installation ID and JWT with the JSON web token: curl --request POST --url "https://api.github.com/app/installations/INSTALLATION_ID/access_tokens" --header "Accept: application/vnd.github+json" --header "Authorization: Bearer JWT" --header "X-GitHub-Api-Version: 2026-03-10".Authorization: Bearer; ordinary tokens generally support either Authorization: Bearer or Authorization: token.repositories or repository_ids, listing at most 500 repositories and never exceeding the installation’s existing repository grant. If neither parameter is supplied, the token covers all repositories granted to the installation.permissions body parameter but cannot exceed the app’s granted permissions; if omitted, the token receives all permissions granted to the app.INSTALLATION_ACCESS_TOKEN with an installation access token in the API example using Authorization: Bearer INSTALLATION_ACCESS_TOKEN for GET https://api.github.com/meta, with Accept: application/vnd.github+json and X-GitHub-Api-Version: 2026-03-10.App from octokit, constructs new App({ appId: APP_ID, privateKey: PRIVATE_KEY }), then obtains an authenticated client with await app.getInstallationOctokit(INSTALLATION_ID); Octokit generates JWTs and refreshes the one-hour installation token automatically. Example requests are await octokit.graphql(...) and await octokit.request("GET /meta").new App({ appId: APP_ID, privateKey: PRIVATE_KEY, webhooks: { WEBHOOK_SECRET } }); pre-authenticated octokit is passed to handlers such as app.webhooks.on("issues.opened", ...), which can call POST /repos/{owner}/{repo}/issues/{issue_number}/comments with API-version header "x-github-api-version": "2026-03-10"./home/byk/Code/getsentry/publish/.github/workflows/auto-approve.yml defines auto-approve non-sdks, triggered only for issues of type opened, with workflow permissions contents: read and issues: write.auto-approve job in .github/workflows/auto-approve.yml runs on ubuntu-latest in protected environment production only when github.actor is sentry-release-bot[bot] or getsantry[bot] and the issue title starts with publish: ..github/workflows/auto-approve.yml checks out only auto-approve-repos.txt using pinned actions/checkout@11d5960a326750d5838078e36cf38b85af677262, with sparse-checkout-cone-mode: false.Get auth token step uses pinned actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 with ${{ vars.SENTRY_INTERNAL_APP_ID }} and protected secret ${{ secrets.SENTRY_INTERNAL_APP_PRIVATE_KEY }}..github/workflows/auto-approve.yml runs node src/publish/record-auto-approval-attestation.js with APPROVAL_TOKEN=${{ github.token }}, the issue number, repository, exact title, and AUTO_APPROVER=${{ github.actor }}; on success it posts ${{ steps.attestation.outputs.auto_approval_attestation }} as an issue comment using gh issue comment..github/workflows/auto-approve.yml extracts REPO using sed -n 's/^publish: \(.*\)@.*/\1/p'; if nonempty and exactly matched by grep -qxF in auto-approve-repos.txt, it adds the accepted label using the GitHub App token and gh issue edit "$ISSUE_URL" --add-label accepted./home/byk/Code/getsentry/publish/src/modules/approval-authorizer.js defines allowed repository roles as new Set(["write", "maintain", "admin"]), AUTO_APPROVAL_LABELER as "sentry-internal-app[bot]", and AUTO_APPROVERS as new Set(["getsantry[bot]", "sentry-release-bot[bot]"]).isAutoApprovedRepository({ actor, autoApprovedRepositories, issueTitle }) rejects actors outside AUTO_APPROVERS and invalid publish titles; otherwise it checks for exact membership of getsentry/${title.repo}${title.path || ""} in autoApprovedRepositories.authorizeApproval({ actor, issueTitle, getPermission }) returns { authorized: false, repository: null } for an invalid publish title. For a valid title it sets repository to getsentry/${title.repo}, rejects both AUTO_APPROVERS and AUTO_APPROVAL_LABELER, and otherwise calls getPermission({ owner: "getsentry", repository: title.repo, username: actor }); authorization is true only when role_name is write, maintain, or admin./home/byk/Code/getsentry/publish/src/modules/approval-attestation.js uses comment prefixes <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready with suffix -->; createAttestation() serializes the value as JSON and encodes it with base64url.requestDigest({ body, labels, title }) throws Invalid publish request unless body is a string and labels is an array; it computes a hexadecimal SHA-256 digest over JSON containing body, dryRun: labels.some((label) => label.name === "dry-run"), and title.createApprovalAttestation({ actor, eventId, issue }) records actor, stringified eventId, requestDigest, and title; createAutoApprovalAttestation({ autoApprover, issue }) records autoApprover, requestDigest, and title; createCiReadyAttestation({ acceptedEvent, ciReadyActor, issue }) records acceptedActor, stringified acceptedEventId, ciReadyActor, requestDigest, and title.parseAttestation(body, prefix) locates the first matching prefix and following -->, decodes the intervening base64url JSON, and returns null for missing delimiters or decoding/parsing failure. parseApprovalAttestation(), parseAutoApprovalAttestation(), and parseCiReadyAttestation() additionally return null unless all required fields are strings.compareEventIds(left, right) stringifies IDs, removes leading zeroes while preserving zero as "0", throws Invalid issue event ID for non-decimal values, and compares arbitrary-size numeric IDs first by normalized length and then via localeCompare().currentLabeledEvent(events, labelName) considers only labeled events for the exact label with a string or numeric id and truthy event.actor.login; it selects the greatest ID via compareEventIds() and returns { actor, eventId: String(id) }, or null if no valid event exists or comparison fails. currentAcceptedEvent() uses label accepted; currentCiReadyEvent() uses ci-ready.hasApprovalAttestation() accepts a comment only when its author equals attestationAuthor and parsed actor, eventId, request digest, and title all match the current event and issue.hasAutoApprovalAttestation() accepts a comment only when its author equals attestationAuthor and parsed autoApprover, request digest, and title match the expected auto approver and current issue.hasCiReadyAttestation() accepts a comment only when its author equals attestationAuthor and parsed acceptedActor, acceptedEventId, ciReadyActor, request digest, and title match the current accepted event, current ci-ready event, and issue.