Skip to content

GitHub Setup

Partner Documentation

Configure your GitHub repository for DCS integration.

Required Setup

1. Azure authentication (OIDC — no long-lived secrets)

DCS deploys with OpenID Connect (OIDC) federated credentials. There is no long-lived client secret and no static Static Web App token to store — the workflow requests a short-lived token at run time and exchanges it with the DCS API for a deployment token.

The generated workflow authenticates with azure/login@v2 using three identifiers, which dcs init writes into .dcs/site.yaml. You can also set them as repository variables (Settings → Secrets and variables → Actions → Variables) — never secrets:

VariableDescription
AZURE_CLIENT_IDApp registration (client) ID with the federated credential
AZURE_TENANT_IDAzure tenant ID
AZURE_SUBSCRIPTION_IDAzure subscription ID

Because these are non-secret identifiers, prefer .dcs/site.yaml (committed) or repository Variables over Secrets.

Set up the federated credential

OIDC works by trusting tokens GitHub Actions mints for your repository, so no password is ever stored. Add a federated credential to the app registration that maps to the branches DCS deploys from (master and release/**):

bash
az ad app federated-credential create \
  --id <AZURE_CLIENT_ID> \
  --parameters '{
    "name": "dcs-deploy-master",
    "issuer": "https://token.actions.githubusercontent.com",
    "subject": "repo:<owner>/<repo>:ref:refs/heads/master",
    "audiences": ["api://AzureADTokenExchange"]
  }'

The DCS team normally provisions the app registration and its federated credentials as part of onboarding — you rarely run this by hand.

2. Copilot Instructions

Create .github/copilot-instructions.md:

markdown
# Copilot Instructions for [Site Name]

## Project Overview

This is a [VitePress/Vue] site integrated with DCS for content management.

## Technology Stack

- **Framework:** VitePress 1.x
- **Styling:** Tailwind CSS
- **Language:** TypeScript
- **Package Manager:** pnpm

## DCS Integration

### Text Content

Use the `useTextContent` composable for all editable text:

\`\`\`vue
<script setup lang="ts">
import { useTextContent } from '@/lib/use-text-content'
const { t } = useTextContent()
</script>

<template>
  <h1>{{ t('section.element', 'Default text') }}</h1>
</template>
\`\`\`

### Text Key Naming

Follow this pattern: `{page}.{section}.{element}`

Examples:
- `home.hero.title`
- `about.team.description`
- `footer.copyright`

## Component Guidelines

1. Use Vue 3 Composition API with `<script setup lang="ts">`
2. Keep components focused and small
3. Use Tailwind for styling
4. Add prop types and emit declarations

## When Creating Pages

1. Add the page to `.dcs/pages.yaml`
2. Use semantic HTML structure
3. Include proper heading hierarchy
4. Add SEO frontmatter

## Development Workflow

1. Branch from release branch (not main)
2. Make changes
3. Test locally with `pnpm dev`
4. Create PR to release branch

## Common Patterns

### Hero Section

\`\`\`vue
<section class="hero">
  <h1>{{ t('page.hero.title', 'Welcome') }}</h1>
  <p>{{ t('page.hero.subtitle', 'Description') }}</p>
</section>
\`\`\`

### Feature Card

\`\`\`vue
<div class="feature-card">
  <Icon :name="icon" />
  <h3>{{ t(\`page.features.\${id}.title\`, title) }}</h3>
  <p>{{ t(\`page.features.\${id}.description\`, description) }}</p>
</div>
\`\`\`

3. Deployment Workflow

dcs init generates .github/workflows/site-deploy.yml for you — you do not hand-write it. It triggers on pushes to master (→ Production) and release/** (→ Preview), and authenticates with OIDC. The load-bearing parts are:

yaml
permissions:
  contents: read
  id-token: write          # required for OIDC — this is what replaces the secret

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Azure login via OIDC
        uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

      - name: Get deployment token
        id: tokens
        run: |
          # OIDC token → DCS API → short-lived SWA deployment token (never stored)
          ACCESS_TOKEN=$(az account get-access-token --resource "api://<dcs-app-id>" --query accessToken -o tsv)
          SWA_TOKEN=$(curl -s -X POST "$PORTAL_API_URL/api/v1/sites/deployment-tokens" \
            -H "Authorization: Bearer $ACCESS_TOKEN" \
            -H "Content-Type: application/json" \
            -d "{\"siteSlug\": \"$SITE_SLUG\"}" | jq -r .swaToken)
          echo "::add-mask::$SWA_TOKEN"
          echo "swa_token=$SWA_TOKEN" >> "$GITHUB_OUTPUT"

      - name: Build site
        run: pnpm install --frozen-lockfile && pnpm run build

      - name: Deploy to Azure Static Web Apps
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ steps.tokens.outputs.swa_token }}
          action: upload
          skip_app_build: true

The Static Web App token is retrieved at deploy time from the DCS API using the OIDC-obtained Azure access token — there is no long-lived deployment token in your repository.

Branch Protection

For main branch:

  • ✅ Require pull request reviews
  • ✅ Require status checks
  • ✅ Require branches to be up to date
  • ✅ Restrict pushes (admin only)

For release/* branches:

  • ✅ Require pull request reviews
  • ✅ Require status checks
  • ⬜ Allow direct pushes for automation

Labels

Create these labels for automation:

LabelColorPurpose
dcs-automation#0052CCDCS-managed issues
development-request#5319E7User dev requests
draft-release#FBCA04Trigger draft deploy
copilot#1D76DBAssigned to Copilot

Webhooks

DCS uses GitHub webhooks for:

  • Issue status tracking
  • PR merge detection
  • Deployment notifications

Webhook Configuration

The DCS server automatically registers webhooks when a site is onboarded. If manual setup is needed:

  1. Go to repository → Settings → Webhooks
  2. Add webhook:
    • URL: https://portal.duffcloudservices.com/api/webhooks/github
    • Content type: application/json
    • Secret: (provided by DCS)
    • Events: Issues, Pull requests, Pushes

GitHub Apps

AI coding agent

DCS assigns an AI coding agent to development-request issues to implement changes as pull requests. The DCS team enables and configures this during onboarding — no per-site setup is required from you.

DCS GitHub App (Optional)

For enhanced integration:

  1. Install the DCS GitHub App
  2. Grant repository access
  3. App handles webhooks automatically

Troubleshooting

Workflow Not Triggering

  1. Check branch protection rules
  2. Verify workflow file syntax
  3. Check for workflow disabled status
  4. Review Actions permissions

OIDC Login Denied

  1. Confirm the workflow has permissions: id-token: write
  2. Verify the app registration has a federated credential whose subject matches the branch or environment being deployed
  3. Check that AZURE_CLIENT_ID / AZURE_TENANT_ID / AZURE_SUBSCRIPTION_ID (variables or .dcs/site.yaml) are correct

Deployment Failures

  1. Confirm the DCS API returned a deployment token (check the token step logs)
  2. Verify build output path
  3. Review Azure resource permissions

Security Best Practices

Credentials

  • Use OIDC federated credentials — never store a long-lived client secret
  • The three Azure identifiers are non-secret; keep them in .dcs/site.yaml or repository Variables, not Secrets
  • Scope federated credentials to the specific branches/environments you deploy

Permissions

  • Limit the app registration's role assignments to the site's resources
  • Use least-privilege access
  • Review access logs regularly

Code

  • Enable Dependabot
  • Review PR changes carefully
  • Use signed commits for production

Next Steps