Appearance
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:
| Variable | Description |
|---|---|
AZURE_CLIENT_ID | App registration (client) ID with the federated credential |
AZURE_TENANT_ID | Azure tenant ID |
AZURE_SUBSCRIPTION_ID | Azure 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: trueThe 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
Recommended Settings
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:
| Label | Color | Purpose |
|---|---|---|
dcs-automation | #0052CC | DCS-managed issues |
development-request | #5319E7 | User dev requests |
draft-release | #FBCA04 | Trigger draft deploy |
copilot | #1D76DB | Assigned 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:
- Go to repository → Settings → Webhooks
- Add webhook:
- URL:
https://portal.duffcloudservices.com/api/webhooks/github - Content type:
application/json - Secret: (provided by DCS)
- Events: Issues, Pull requests, Pushes
- URL:
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:
- Install the DCS GitHub App
- Grant repository access
- App handles webhooks automatically
Troubleshooting
Workflow Not Triggering
- Check branch protection rules
- Verify workflow file syntax
- Check for workflow disabled status
- Review Actions permissions
OIDC Login Denied
- Confirm the workflow has
permissions: id-token: write - Verify the app registration has a federated credential whose
subjectmatches the branch or environment being deployed - Check that
AZURE_CLIENT_ID/AZURE_TENANT_ID/AZURE_SUBSCRIPTION_ID(variables or.dcs/site.yaml) are correct
Deployment Failures
- Confirm the DCS API returned a deployment token (check the token step logs)
- Verify build output path
- 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.yamlor 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
- site.yaml Reference — Site identity and deployment configuration
- Deployment — Deployment workflows
- Release Management — Version control
