Dashboard › publish › Session 1UQmEiyDEYMA
1UQmEiyDEYMAMJpc6READ ONLY. Produce a NON-EMPTY file-by-file merge map for integrating origin/main commit 7c60ddb into the dirty current worktree at /home/byk/Code/getsentry/publish. Scope ONLY .github/workflows/ci-poller.yml, .github/workflows/publish.yml, .github/workflows/cocoapods-keepalive.yml, src/modules/__tests__/ci-poller-workflow.js, and src/modules/__tests__/publish-workflow.js. Compare HEAD, origin/main, and current worktree. Identify every upstream workspace/revision/state behavior, exact current and upstream line evidence, overlap with current attestation/relay/action-pinning/Craft-digest hardening, and the exact merged step order and variables. Never edit or format files. If any tool fails, report the exact error. Do not return empty.
I will freeze the three comparison points first, then trace only the five named files across HEAD, 7c60ddb/origin/main, and the worktree. The report will cite exact lines and give a conflict-aware merged workflow order without changing files.
<path>/home/byk/Code/getsentry/publish</path> <type>directory</type> <entries> .eslintrc.js .git/ .github/ .gitignore .lore.md AGENTS.md auto-approve-repos.txt docs/ LICENSE node_modules/ package.json README.md src/ vitest.config.js yarn.lock (15 entries) </entries>
[
{
"content": "Freeze HEAD, origin/main, target commit, and scoped worktree status",
"status": "in_progress",
"priority": "high"
},
{
"content": "Compare all five scoped files across HEAD, upstream, and worktree",
"status": "pending",
"priority": "high"
},
{
"content": "Trace upstream behavior and hardening overlap with exact line evidence",
"status": "pending",
"priority": "high"
},
{
"content": "Produce the file-by-file merge map and exact merged step order/variables",
"status": "pending",
"priority": "high"
}
]
## main...origin/main [behind 1] M .github/workflows/auto-approve.yml M .github/workflows/ci-poller.yml M .github/workflows/cocoapods-keepalive.yml M .github/workflows/publish.yml M .github/workflows/test.yml M AGENTS.md M README.md M docs/key_rotation_vault_changes.md M docs/rfc.md M src/libs/__tests__/github.js M src/libs/github.js M src/modules/__tests__/details-from-context.js M src/modules/__tests__/update-issue.js M src/modules/details-from-context.js M src/modules/post-workflow-details.js M src/modules/process-end-state.js M src/modules/update-issue.js M src/publish/inputs.js M src/publish/post-result.js M src/publish/post-workflow-details.js M src/publish/update-issue.js ?? .github/workflows/ci-poller-dispatch.yml ?? .lore.md ?? src/modules/__tests__/approval-attestation.js ?? src/modules/__tests__/approval-authorizer.js ?? src/modules/approval-attestation.js ?? src/modules/approval-authorizer.js ?? src/publish/__tests__/ ?? ...
83d210b29553ea6f4d97508821724a834c43856e 7c60ddb7f43040fe8fbfea70efc833f689c04e75 7c60ddb7f43040fe8fbfea70efc833f689c04e75
83d210b29553ea6f4d97508821724a834c43856e
7c60ddb feat: accept workspace publish requests .github/workflows/ci-poller.yml | 62 +++++---- .github/workflows/cocoapods-keepalive.yml | 2 +- .github/workflows/publish.yml | 84 ++++++------ src/modules/__tests__/ci-poller-workflow.js | 197 ++++++++++++++++++++++++++++ src/modules/__tests__/publish-workflow.js | 156 ++++++++++++++++++++++ 5 files changed, 435 insertions(+), 66 deletions(-)
M .github/workflows/ci-poller.yml M .github/workflows/cocoapods-keepalive.yml M .github/workflows/publish.yml A src/modules/__tests__/ci-poller-workflow.js A src/modules/__tests__/publish-workflow.js
M .github/workflows/ci-poller.yml M .github/workflows/cocoapods-keepalive.yml M .github/workflows/publish.yml
[
{
"content": "Freeze HEAD, origin/main, target commit, and scoped worktree status",
"status": "completed",
"priority": "high"
},
{
"content": "Compare all five scoped files across HEAD, upstream, and worktree",
"status": "in_progress",
"priority": "high"
},
{
"content": "Trace upstream behavior and hardening overlap with exact line evidence",
"status": "pending",
"priority": "high"
},
{
"content": "Produce the file-by-file merge map and exact merged step order/variables",
"status": "pending",
"priority": "high"
}
]
The base is exact: HEAD is 83d210b, and origin/main plus 7c60ddb^{commit} both resolve to 7c60ddb7; HEAD is their merge base. Upstream changes all five scoped files, while the worktree changes the three workflows and does not yet contain either new upstream test file, so every workflow needs a three-way merge and both tests need addition-plus-hardening reconciliation.
<path>/home/byk/Code/getsentry/publish/.github/workflows/ci-poller.yml</path> <type>file</type> <content> 1: name: CI Status Poller 2: 3: on: 4: schedule: 5: - cron: "*/5 * * * *" 6: repository_dispatch: 7: types: [ci-poller] 8: workflow_run: 9: workflows: [Run CI Status Poller] 10: types: [completed] 11: 12: permissions: 13: contents: read 14: issues: write 15: 16: jobs: 17: check-ci: 18: runs-on: ubuntu-latest 19: environment: production 20: # Skip entirely (no runner provisioned) when there's nothing to check. 21: # Set to "true" by ci-pending.yml, reset to "false" here when done. 22: # repository_dispatch and a successful main-branch run of the protected 23: # workflow_dispatch relay are the trusted manual-recovery paths. 24: if: >- 25: vars.CI_POLLER_HAS_PENDING == 'true' 26: || github.event_name == 'repository_dispatch' 27: || ( 28: github.event_name == 'workflow_run' 29: && ...
<path>/home/byk/Code/getsentry/publish/.github/workflows/publish.yml</path>
<type>file</type>
<content>
1: name: Publish
2: on:
3: issues:
4: types: [labeled]
5:
6: concurrency:
7: # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
8: # issues for the same repo@version share a concurrency group.
9: group: ${{ github.event.issue.title }}
10: cancel-in-progress: false
11:
12: permissions:
13: contents: read
14: issues: write
15: packages: write
16:
17: jobs:
18: # When accepted is added to a publish issue:
19: # - Add ci-pending (and remove ci-failed if retrying)
20: # - Enable the poller via CI_POLLER_HAS_PENDING=true
21: # - Comment on the issue
22: # - Trigger the poller immediately so we don't wait for the next cron tick
23: # The publish job below requires ci-ready, so it will not fire until the
24: # poller flips ci-pending → ci-ready (which also prevents publishing without
25: # CI verification in the ...
<path>/home/byk/Code/getsentry/publish/.github/workflows/cocoapods-keepalive.yml</path>
<type>file</type>
<content>
1: name: CocoaPods Token Keep-Alive
2:
3: on:
4: schedule:
5: # CocoaPods sessions currently expire after 3 days of inactivity (VALIDITY_LENGTH)
6: # This runs every day at midnight UTC to keep the current token alive
7: # See: https://github.com/CocoaPods/trunk.cocoapods.org/blob/a1869790e9ae2229b6985b6af4532da814202558/app/models/session.rb#L9
8: - cron: "0 0 * * *" # Runs every day at midnight UTC
9:
10: permissions:
11: contents: read
12:
13: jobs:
14: keepalive:
15: name: Refresh CocoaPods Session
16: runs-on: macos-15
17: environment: production
18: env:
19: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
20:
21: steps:
22: - name: Install CocoaPods
23: run: gem install cocoapods
24: - name: Print CocoaPods Version
25: run: pod --version
26: - name: Refresh CocoaPods ...
No files found
commit 7c60ddb7f43040fe8fbfea70efc833f689c04e75
Author: Burak Yigit Kaya <byk@sentry.io>
AuthorDate: Tue Sep 8 18:37:21 2026 +0100
Commit: GitHub <noreply@github.com>
CommitDate: Tue Sep 8 17:37:21 2026 +0000
feat: accept workspace publish requests
## Summary
- Parse and validate workspace-qualified publish request titles.
- Propagate the selected workspace into Craft and isolate secure
publish-resume state by workspace.
- Restore failed target state only from the workflow-created XDG state
file.
## Validation
- pnpm test: 6 files, 25 tests passed.
- Focused workflow-state regression: 3 files, 18 tests passed.
- Prettier and changed-file ESLint passed.
## Deployment
Deploy this controller before Craft PR #872. It adds the title parser
and secure state contract required for workspace-qualified requests.
diff --git a/.github/workflows/ci-poller.yml b/.github/workflows/ci-poller.yml
index a3db430..487e9da 100644
--- a/.github/workflows/ci-poller.yml
+++ b/.github/workflows/ci-poller.yml
@@ -1,314 +1,324 @@
name: CI Status Poller
on:
schedule:
- cron: "*/5 * * * *"
workflow_dispatch:
inputs:
attempt:
description: Self-dispatch attempt counter (internal use)
required: false
default: "0"
permissions:
contents: read
issues: read
jobs:
check-ci:
runs-on: ubuntu-latest
environment: production
# Skip entirely (no runner provisioned) when there's nothing to check.
# Set to "true" by ci-pending.yml, reset to "false" here when done.
# Always allow workflow_dispatch for manual recovery.
if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch'
concurrency:
group: ci-status-poller
cancel-in-progress: false
steps:
# sentry-internal-app token ...
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index cff6bc3..2635ea6 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -20,293 +20,299 @@ jobs:
# - Enable the poller via CI_POLLER_HAS_PENDING=true
# - Comment on the issue
# - Trigger the poller immediately so we don't wait for the next cron tick
# The publish job below requires ci-ready, so it will not fire until the
# poller flips ci-pending → ci-ready (which also prevents publishing without
# CI verification in the auto-approve race).
waiting-for-ci:
runs-on: ubuntu-latest
name: Waiting for CI
environment: production
if: >-
github.event.label.name == 'accepted'
&& github.event.issue.state == 'open'
&& startsWith(github.event.issue.title, 'publish: ')
steps:
- name: Get auth token
id: token
uses: actions/create-github-app-token@v3
with:
client-id: ${{ ...
diff --git a/.github/workflows/cocoapods-keepalive.yml b/.github/workflows/cocoapods-keepalive.yml
index 21c0696..9c11b0e 100644
--- a/.github/workflows/cocoapods-keepalive.yml
+++ b/.github/workflows/cocoapods-keepalive.yml
@@ -1,28 +1,28 @@
-name: "CocoaPods Token Keep-Alive"
+name: CocoaPods Token Keep-Alive
on:
schedule:
# CocoaPods sessions currently expire after 3 days of inactivity (VALIDITY_LENGTH)
# This runs every day at midnight UTC to keep the current token alive
# See: https://github.com/CocoaPods/trunk.cocoapods.org/blob/a1869790e9ae2229b6985b6af4532da814202558/app/models/session.rb#L9
- cron: "0 0 * * *" # Runs every day at midnight UTC
workflow_dispatch:
permissions:
contents: read
jobs:
keepalive:
name: Refresh CocoaPods Session
runs-on: macos-15
environment: production
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
steps:
- name: Install CocoaPods
run: gem ...
diff --git a/.github/workflows/ci-poller.yml b/.github/workflows/ci-poller.yml
index a3db430..f734db7 100644
--- a/.github/workflows/ci-poller.yml
+++ b/.github/workflows/ci-poller.yml
@@ -1,314 +1,463 @@
name: CI Status Poller
on:
schedule:
- cron: "*/5 * * * *"
- workflow_dispatch:
- inputs:
- attempt:
- description: Self-dispatch attempt counter (internal use)
- required: false
- default: "0"
+ repository_dispatch:
+ types: [ci-poller]
+ workflow_run:
+ workflows: [Run CI Status Poller]
+ types: [completed]
permissions:
contents: read
- issues: read
+ issues: write
jobs:
check-ci:
runs-on: ubuntu-latest
environment: production
# Skip entirely (no runner provisioned) when there's nothing to check.
# Set to "true" by ci-pending.yml, reset to "false" here when done.
- # Always allow workflow_dispatch for manual recovery.
- if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == ...
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index cff6bc3..9ff9a9d 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,312 +1,435 @@
name: Publish
on:
issues:
types: [labeled]
concurrency:
# Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
# issues for the same repo@version share a concurrency group.
group: ${{ github.event.issue.title }}
cancel-in-progress: false
permissions:
contents: read
issues: write
packages: write
jobs:
# When accepted is added to a publish issue:
# - Add ci-pending (and remove ci-failed if retrying)
# - Enable the poller via CI_POLLER_HAS_PENDING=true
# - Comment on the issue
# - Trigger the poller immediately so we don't wait for the next cron tick
# The publish job below requires ci-ready, so it will not fire until the
# poller flips ci-pending → ci-ready (which also prevents publishing without
# CI ...
diff --git a/.github/workflows/cocoapods-keepalive.yml b/.github/workflows/cocoapods-keepalive.yml
index 21c0696..ffa5982 100644
--- a/.github/workflows/cocoapods-keepalive.yml
+++ b/.github/workflows/cocoapods-keepalive.yml
@@ -1,28 +1,27 @@
-name: "CocoaPods Token Keep-Alive"
+name: CocoaPods Token Keep-Alive
on:
schedule:
# CocoaPods sessions currently expire after 3 days of inactivity (VALIDITY_LENGTH)
# This runs every day at midnight UTC to keep the current token alive
# See: https://github.com/CocoaPods/trunk.cocoapods.org/blob/a1869790e9ae2229b6985b6af4532da814202558/app/models/session.rb#L9
- cron: "0 0 * * *" # Runs every day at midnight UTC
- workflow_dispatch:
permissions:
contents: read
jobs:
keepalive:
name: Refresh CocoaPods Session
runs-on: macos-15
environment: production
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
steps:
- name: Install CocoaPods
run: gem ...
1 import {
2 mkdtempSync,
3 mkdirSync,
4 readFileSync,
5 readdirSync,
6 rmSync,
7 writeFileSync,
8 } from "fs";
9 import { tmpdir } from "os";
10 import { join } from "path";
11 import { spawnSync } from "child_process";
12
13 import { afterEach, expect, test } from "vitest";
14
15 const temporaryDirectories = [];
16 const INITIAL_REVISION = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
17 const UPDATED_REVISION = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
18
19 function getPollerScript() {
20 const workflow = readFileSync(
21 join(__dirname, "../../../.github/workflows/ci-poller.yml"),
22 "utf8"
23 );
24 const section = workflow.match(
25 / {6}- name: Check CI status for ci-pending issues[\s\S]*? {8}run: \|\n(?<script>[\s\S]*?)\n {6}- name: Check for remaining pending issues/
26 );
27
28 if (!section?.groups?.script) {
29 ...
1 import { spawnSync } from "child_process";
2 import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
3 import { tmpdir } from "os";
4 import { join } from "path";
5
6 import { afterEach, expect, test } from "vitest";
7
8 const { resolvePublishLocation } = require("../publish-location.js");
9
10 const temporaryDirectories = [];
11
12 function getWorkflow() {
13 return readFileSync(
14 join(__dirname, "../../../.github/workflows/publish.yml"),
15 "utf8"
16 );
17 }
18
19 function getSetTargetsScript() {
20 const workflow = getWorkflow();
21 const section = workflow.match(
22 / {6}- name: Set targets[\s\S]*? {8}run: \|\n(?<script>[\s\S]*?)\n {6}- uses: docker:\/\/getsentry\/craft:latest/
23 );
24 if (!section?.groups?.script) {
25 throw new Error("Missing Set targets workflow script");
26 }
27 return ...