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 ​