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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

## [1.0.0] - 2025-08-25

### Added
- Added support for Gandi DNS provider

### Fixed
- Support `workflow_run` events for correct GitHub commit status (e.g., secure fork PR workflows)

## [0.1.0] - 2025-02-20

- Initial release of of the dnslink-action
133 changes: 125 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ This action is built and maintained by [Interplanetary Shipyard](http://ipshipya

It's a [composite action](https://docs.github.com/en/actions/sharing-automations/creating-actions/about-custom-actions#composite-actions) that can be called as a step in your workflow to set the DNSLink TXT record for a given domain.

## Table of Contents

- [Inputs](#inputs)
- [Required Inputs](#required-inputs)
- [Optional Inputs](#optional-inputs)
- [Usage](#usage)
- [Simple Workflow (No Fork PRs)](#simple-workflow-no-fork-prs)
- [Dual Workflows (With Fork PRs)](#dual-workflows-with-fork-prs)
- [FAQ](#faq)

## Inputs

### Required Inputs
Expand All @@ -38,10 +48,9 @@ It's a [composite action](https://docs.github.com/en/actions/sharing-automations

## Usage

See the [IPNS Inspector](https://github.com/ipfs/ipns-inspector/blob/main/.github/workflows/build.yml) for a real-world example of this action in use.

### Simple Workflow (No Fork PRs)

Here's a basic example of how to use this action in your workflow:
For repositories that don't accept PRs from forks, you can use a single workflow:

```yaml
name: Build and Deploy to IPFS
Expand Down Expand Up @@ -78,27 +87,135 @@ jobs:
- name: Build project
run: npm run build

- uses: ipfs/ipfs-deploy-action@v0.3
name: Deploy to IPFS
- name: Deploy to IPFS
uses: ipshipyard/ipfs-deploy-action@v1
id: deploy
with:
path-to-deploy: out
storacha-key: ${{ secrets.STORACHA_KEY }}
storacha-proof: ${{ secrets.STORACHA_PROOF }}
github-token: ${{ github.token }}

- uses: ipfs/dnslink-action@v0.1
- name: Update DNSLink
uses: ipshipyard/dnslink-action@v1
if: github.ref == 'refs/heads/main' # only update the DNSLink on the main branch
name: Update DNSLink
with:
cid: ${{ steps.deploy.outputs.cid }} # The CID of the build to update the DNSLink for
cid: ${{ steps.deploy.outputs.cid }}
dnslink_domain: mydomain.com
cf_record_id: ${{ secrets.CF_RECORD_ID }}
cf_zone_id: ${{ secrets.CF_ZONE_ID }}
cf_auth_token: ${{ secrets.CF_AUTH_TOKEN }}
```

### Dual Workflows (For Secure Fork PRs)

For secure deployments of PRs from forks, use two separate workflows that pass artifacts between them:

**`.github/workflows/build.yml`** - Builds without secrets access:
```yaml
name: Build

permissions:
contents: read

on:
push:
branches:
- main
pull_request:
branches:
- main

env:
BUILD_PATH: 'out' # Update this to your build output directory

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}


- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build project
run: npm run build

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: website-build-${{ github.run_id }}
path: ${{ env.BUILD_PATH }}
retention-days: 1
```

**`.github/workflows/deploy.yml`** - Deploys with secrets access:
```yaml
name: Deploy

permissions:
contents: read
pull-requests: write
statuses: write

on:
workflow_run:
workflows: ["Build"]
types: [completed]

env:
BUILD_PATH: 'website-build' # Directory where artifact from build.yml will be unpacked

jobs:
deploy-ipfs:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
outputs: # This exposes the CID output of the action to the rest of the workflow
cid: ${{ steps.deploy.outputs.cid }}
steps:
- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: website-build-${{ github.event.workflow_run.id }}
path: ${{ env.BUILD_PATH }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}

- name: Deploy to IPFS
uses: ipshipyard/ipfs-deploy-action@v1
id: deploy
with:
path-to-deploy: ${{ env.BUILD_PATH }}
storacha-key: ${{ secrets.STORACHA_KEY }}
storacha-proof: ${{ secrets.STORACHA_PROOF }}
github-token: ${{ github.token }}

- name: Update DNSLink
uses: ipshipyard/dnslink-action@v1
if: github.event.workflow_run.head_branch == 'main' # only update for main branch
with:
cid: ${{ steps.deploy.outputs.cid }}
dnslink_domain: mydomain.com
cf_record_id: ${{ secrets.CF_RECORD_ID }}
cf_zone_id: ${{ secrets.CF_ZONE_ID }}
cf_auth_token: ${{ secrets.CF_AUTH_TOKEN }}
github_token: ${{ github.token }}
set_github_status: true
```

## FAQ

- Why not use an infrastructure-as-code tool like [OctoDNS](https://github.com/octodns/octodns) or [DNSControl](https://github.com/StackExchange/dnscontrol)?
- You can! Those are great tools.
- How can I safely build on PRs from forks?
- Use the two-workflow pattern shown above. The build workflow runs on untrusted fork code without secrets access, while the deploy workflow only runs after a successful build and has access to secrets but never executes untrusted code. This pattern uses GitHub's `workflow_run` event to securely pass artifacts between workflows.
16 changes: 12 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,18 @@ runs:
script: |
const cid = '${{ inputs.cid }}';

// For PR events, we need to use the head SHA
const sha = context.eventName === 'pull_request'
? context.payload.pull_request.head.sha
: context.sha;
// Determine the correct SHA based on the event type
let sha;
if (context.eventName === 'workflow_run') {
// For workflow_run events triggered by PRs, use the PR's head SHA
sha = context.payload.workflow_run.head_sha;
} else if (context.eventName === 'pull_request' || context.eventName === 'pull_request_target') {
// For PR events, use the head SHA
sha = context.payload.pull_request.head.sha;
} else {
// For push events, use the commit SHA
sha = context.sha;
}

await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
Expand Down