Skip to content

Build and Push

Build and Push #158

Workflow file for this run

name: Build and Push
on:
push:
tags:
- "v*"
schedule:
# Weekly rebuild on Mondays at 04:00 UTC to pick up fresh base image packages
- cron: "0 4 * * 1"
workflow_dispatch:
permissions:
contents: read
packages: write
id-token: write
attestations: write
concurrency:
group: build-${{ github.ref }}
cancel-in-progress: true
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set GHCR image name
run: echo "GHCR_IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v6
with:
images: |
${{ env.GHCR_IMAGE }}
canvascoding/canvas-notebook
tags: |
type=ref,event=tag
type=raw,value=latest
- name: Build and push
id: build
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
push: true
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: mode=max
sbom: true
no-cache: ${{ github.event_name == 'schedule' }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Notify Control Plane release webhook
env:
CONTROL_PLANE_RELEASE_WEBHOOK_URL: ${{ secrets.CONTROL_PLANE_RELEASE_WEBHOOK_URL }}
CONTROL_PLANE_RELEASE_WEBHOOK_SECRET: ${{ secrets.CONTROL_PLANE_RELEASE_WEBHOOK_SECRET }}
DOCKER_METADATA_TAGS: ${{ steps.meta.outputs.tags }}
IMAGE_DIGEST: ${{ steps.build.outputs.digest }}
run: |
if [ -z "${CONTROL_PLANE_RELEASE_WEBHOOK_URL}" ]; then
echo "CONTROL_PLANE_RELEASE_WEBHOOK_URL secret is missing."
exit 1
fi
if [ -z "${CONTROL_PLANE_RELEASE_WEBHOOK_SECRET}" ]; then
echo "CONTROL_PLANE_RELEASE_WEBHOOK_SECRET secret is missing."
exit 1
fi
node --input-type=module <<'NODE'
import crypto from 'node:crypto';
import fs from 'node:fs';
const tags = (process.env.DOCKER_METADATA_TAGS || '')
.split(/\r?\n/)
.map((tag) => tag.trim())
.filter(Boolean);
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const isTag = process.env.GITHUB_REF_TYPE === 'tag';
const tag = isTag ? process.env.GITHUB_REF_NAME || '' : '';
const eventName = process.env.GITHUB_EVENT_NAME || '';
const event = isTag ? 'release_published' : eventName === 'schedule' ? 'image_rebuilt' : 'image_pushed';
const version = tag ? tag.replace(/^v/i, '') : String(packageJson.version || '');
const payload = {
event,
repository: process.env.GITHUB_REPOSITORY,
ref: process.env.GITHUB_REF,
tag: tag || undefined,
version,
commitSha: process.env.GITHUB_SHA,
image: {
name: process.env.GHCR_IMAGE,
tags,
digest: process.env.IMAGE_DIGEST || undefined,
},
workflow: {
runId: process.env.GITHUB_RUN_ID,
runNumber: process.env.GITHUB_RUN_NUMBER,
runAttempt: process.env.GITHUB_RUN_ATTEMPT,
},
source: 'github_actions',
publishedAt: new Date().toISOString(),
metadata: {
actor: process.env.GITHUB_ACTOR,
eventName,
workflow: process.env.GITHUB_WORKFLOW,
},
};
const body = JSON.stringify(payload);
const timestamp = Math.floor(Date.now() / 1000).toString();
const delivery = `${process.env.GITHUB_RUN_ID}-${process.env.GITHUB_RUN_ATTEMPT}-${process.env.GITHUB_SHA}`;
const signature = 'sha256=' + crypto
.createHmac('sha256', process.env.CONTROL_PLANE_RELEASE_WEBHOOK_SECRET)
.update(`${timestamp}.${body}`)
.digest('hex');
const response = await fetch(process.env.CONTROL_PLANE_RELEASE_WEBHOOK_URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-canvas-delivery': delivery,
'x-canvas-timestamp': timestamp,
'x-canvas-signature': signature,
},
body,
});
const text = await response.text();
if (!response.ok) {
console.error(`Control Plane release webhook failed (${response.status}): ${text}`);
process.exit(1);
}
console.log(`Control Plane release webhook accepted: ${text}`);
NODE