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
35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,41 @@ jobs:
with:
release_tag: v${{ needs.plan.outputs.version }}

# agent-device.dev serves /.well-known/mcp.json with the npm `latest` version read when the
# site builds. A tag push builds nothing on Vercel, so ask for a production build of main once
# npm serves the new version. The VERCEL_SITE_DEPLOY_HOOK secret holds the Vercel deploy hook
# of the agent-device-website project for main; it is the only secret this workflow reads.
redeploy-site:
name: Redeploy agent-device.dev
needs: [plan, publish]
if: needs.plan.outputs.mode == 'stable'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions: {}
steps:
# Any latest at or past this version will do: a newer stable release may already have
# moved latest on, and the site only needs the current one.
- name: Wait for npm to serve this release or a newer one as latest
env:
VERSION: ${{ needs.plan.outputs.version }}
run: |
for attempt in $(seq 1 30); do
latest="$(npm view agent-device@latest version 2>/dev/null || true)"
if [ -n "$latest" ] &&
[ "$(printf '%s\n' "$VERSION" "$latest" | sort -V | head -n 1)" = "$VERSION" ]; then
echo "npm serves $latest as latest."
exit 0
fi
sleep 10
done
echo "npm does not serve $VERSION or newer as latest after 5 minutes."
exit 1

- name: Trigger the site's production build
env:
DEPLOY_HOOK: ${{ secrets.VERCEL_SITE_DEPLOY_HOOK }}
Comment thread
thymikee marked this conversation as resolved.
Resolved
run: curl -fsS -X POST "$DEPLOY_HOOK" > /dev/null

mark-released:
name: Move main past ${{ needs.plan.outputs.version }}
needs: [plan, publish]
Expand Down
14 changes: 13 additions & 1 deletion test/ci/release-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,20 @@ test('only the npm publisher and the MCP Registry call can mint an id-token', ()
expect(workflow.jobs.publish?.environment).toBe('npm-publish');
});

/** The secret names a job references, wherever in the job they appear. */
const secretsOf = (job: Job) =>
[...JSON.stringify(job).matchAll(/secrets\.([A-Za-z0-9_]+)/g)].map(([, name]) => name);

test('the publisher authenticates through OIDC alone', () => {
expect(source).not.toMatch(/NPM_TOKEN|NODE_AUTH_TOKEN|secrets\./);
expect(source).not.toMatch(/NPM_TOKEN|NODE_AUTH_TOKEN/);
// No secret reaches the jobs that build or publish the packages. The one secret in the file
// is the site's deploy hook, which only the redeploy job after a stable release reads.
expect(secretsOf(workflow.jobs.publish ?? {})).toEqual([]);
expect(secretsOf(workflow.jobs.build ?? {})).toEqual([]);
const withSecrets = Object.entries(workflow.jobs)
.map(([name, job]) => [name, secretsOf(job)] as const)
.filter(([, names]) => names.length > 0);
expect(withSecrets).toEqual([['redeploy-site', ['VERCEL_SITE_DEPLOY_HOOK']]]);
const setupNode = workflow.jobs.publish?.steps?.find((step) =>
step.uses?.startsWith('actions/setup-node@'),
);
Expand Down
9 changes: 5 additions & 4 deletions website/src/pages/.well-known/mcp.json.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// /.well-known/mcp.json: the stdio MCP server's registry identity, from the repo's server.json,
// with the version set to the latest one published on npm when the site is built. The site
// redeploys on every push to main, so the version follows releases. Without npm the build
// fails: server.json between releases carries an unpublished `-dev` version, and agents would
// be told to install a package that does not exist.
// with the version set to the latest one published on npm when the site is built. The release
// workflow (release.yml, redeploy-site) rebuilds the site right after each stable release, so
// the version follows releases. Without npm the build fails: server.json between releases
// carries an unpublished `-dev` version, and agents would be told to install a package that
// does not exist.
import type { APIRoute } from 'astro';

import server from '../../../../server.json';
Expand Down
Loading