diff --git a/.github/workflows/_deploy-gated.yml b/.github/workflows/_deploy-gated.yml index ca8679f73..cc73594cb 100644 --- a/.github/workflows/_deploy-gated.yml +++ b/.github/workflows/_deploy-gated.yml @@ -52,6 +52,7 @@ jobs: run: yarn build env: NODE_ENV: production + STAGE: ${{ inputs.stage }} BRANCH: ${{ github.ref_name }} - name: CDK-Dependencies installieren diff --git a/.github/workflows/_deploy.yml b/.github/workflows/_deploy.yml index 2adc3b0fe..9568d295f 100644 --- a/.github/workflows/_deploy.yml +++ b/.github/workflows/_deploy.yml @@ -54,6 +54,7 @@ jobs: run: yarn build env: NODE_ENV: production + STAGE: ${{ inputs.stage }} # CDK-Projekt (npm). esbuild für das Lambda-Bundling wird aus dem # Repo-Root (yarn) aufgelöst und muss dort nicht erneut installiert werden diff --git a/cdk/DEPLOYMENT.md b/cdk/DEPLOYMENT.md index d93ac9746..3f9370a68 100644 --- a/cdk/DEPLOYMENT.md +++ b/cdk/DEPLOYMENT.md @@ -7,9 +7,11 @@ Im Zuge der App-Erneuerung wurde das Deployment im Mai 2026 vom Serverless Frame | Stage | Domain | Projekt-Bucket | |-------|--------|----------------| | `dev` | `dev.maus.metahost.org` | `pmdm-projectbucket-dev-` | -| `staging` | `staging.code4maus.wt.wdr.cloud` | `pmdm-projectbucket-staging-` | +| `staging` | `staging.maus.metahost.org` | `pmdm-projectbucket-staging-` | | `prod` | `programmieren.wdrmaus.de` | `pmdm-projectbucket-prod-` | +Die Domains stehen in `lib/stage-domains.json`. Der Frontend-Build liest sie ebenfalls, für die Seiten-URLs in den Meta-Tags; die Deploy-Workflows geben ihm dafür die Stage per `STAGE` mit. + Die aktive Stage wird über die Umgebungsvariable `STAGE` oder den CDK-Kontext-Parameter `--context stage=` gesetzt. Ohne Angabe wird `dev` verwendet. ## Infrastruktur-Komponenten diff --git a/cdk/lib/config.ts b/cdk/lib/config.ts index 95664d158..21c168eef 100644 --- a/cdk/lib/config.ts +++ b/cdk/lib/config.ts @@ -1,3 +1,5 @@ +import STAGE_DOMAINS from './stage-domains.json' + export type StageName = 'prod' | 'staging' | 'dev' export interface StageConfig { @@ -44,7 +46,7 @@ const PLACEHOLDER_CERT_ARN = // (`aws route53 list-hosted-zones`). export const STAGES: Record = { prod: { - domain: 'programmieren.wdrmaus.de', + domain: STAGE_DOMAINS.prod, certArn: PLACEHOLDER_CERT_ARN, // hostedZoneId: 'TODO_PROD_HOSTED_ZONE_ID', // hostedZoneName: 'wdrmaus.de.', @@ -52,7 +54,7 @@ export const STAGES: Record = { region: DEFAULT_REGION, }, staging: { - domain: 'staging.maus.metahost.org', + domain: STAGE_DOMAINS.staging, certArn: 'arn:aws:acm:us-east-1:391322831368:certificate/c7376bf1-8253-42e3-9385-da8bfaa1ae18', // hostedZoneId: 'TODO_STAGING_HOSTED_ZONE_ID', @@ -61,7 +63,7 @@ export const STAGES: Record = { region: DEFAULT_REGION, }, dev: { - domain: 'dev.maus.metahost.org', + domain: STAGE_DOMAINS.dev, certArn: 'arn:aws:acm:us-east-1:391322831368:certificate/b2d1f159-5248-4f44-9bef-b94f9b69b260', // hostedZoneId: 'TODO_DEV_HOSTED_ZONE_ID', diff --git a/cdk/lib/stage-domains.json b/cdk/lib/stage-domains.json new file mode 100644 index 000000000..9067cd04c --- /dev/null +++ b/cdk/lib/stage-domains.json @@ -0,0 +1,5 @@ +{ + "prod": "programmieren.wdrmaus.de", + "staging": "staging.maus.metahost.org", + "dev": "dev.maus.metahost.org" +} diff --git a/cdk/tsconfig.json b/cdk/tsconfig.json index bfc61bf83..172090396 100644 --- a/cdk/tsconfig.json +++ b/cdk/tsconfig.json @@ -21,6 +21,7 @@ "experimentalDecorators": true, "strictPropertyInitialization": false, "skipLibCheck": true, + "resolveJsonModule": true, "typeRoots": [ "./node_modules/@types" ] diff --git a/package.json b/package.json index c8854840c..a1aff57b0 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,6 @@ "postcss-mixins": "^6.2.0", "postcss-simple-vars": "^5.0.2", "prettier": "^2.0.2", - "promise-timeout": "^1.3.0", "prop-types": "^15.5.10", "raf": "^3.4.0", "raw-loader": "^2.0.0", diff --git a/scripts/env.js b/scripts/env.js index 55e626739..3575bc8b7 100644 --- a/scripts/env.js +++ b/scripts/env.js @@ -1,101 +1,20 @@ -/* eslint-disable no-console */ -const AWS = require('aws-sdk') -const { timeout } = require('promise-timeout') - -const getHostedZoneForDomain = (domain) => { - const route53 = new AWS.Route53({ - region: 'eu-central-1', - }) - const splittedDomain = domain.split('.') - let foundId = null - return timeout(route53.listHostedZones({}).promise(), 5000) - .then((data) => { - return splittedDomain.every((_part, i) => { - const domain = splittedDomain.slice(i).join('.') + '.' - const result = data.HostedZones.find((zone) => zone.Name === domain) - if (result === undefined) { - return true - } - foundId = result.Id - return false // break - }) - }) - .then((notFound) => (!notFound ? foundId : null)) -} - -const getCertArnForDomain = (domain) => { - const acm = new AWS.ACM({ - region: 'us-east-1', - }) - const wildCardDomain = '*.' + domain.split('.').slice(1).join('.') - return timeout(acm.listCertificates({}).promise(), 5000) - .then((data) => - data.CertificateSummaryList.find( - (cert) => - cert.DomainName === domain || cert.DomainName === wildCardDomain - ) +const stageDomains = require('../cdk/lib/stage-domains.json') + +// Deploy workflows set STAGE; local and preview builds fall back to dev. +const stage = () => process.env.STAGE || 'dev' + +const baseDomain = () => { + const domain = stageDomains[stage()] + if (!domain) { + throw new Error( + `Unknown stage: ${stage()}. Expected one of: ${Object.keys( + stageDomains + ).join(', ')}.` ) - .then((cert) => cert && cert.CertificateArn) -} - -const stageFromBranch = () => { - const branch = process.env.BRANCH || process.env.TRAVIS_BRANCH - if (branch === 'production') { - return 'prod' - } - if (branch === 'develop') { - return 'staging' } - return false -} - -const stage = () => process.env.SLS_STAGE || stageFromBranch() || 'dev' - -const baseDomain = () => - stage() === 'prod' - ? 'programmieren.wdrmaus.de' - : `${stage()}.code4maus.wt.wdr.cloud` - -const bucketSuffix = () => (stage() === 'prod' ? 'prod' : 'staging') - -const hostedZone = () => { - const domain = baseDomain() - return getHostedZoneForDomain(domain) - .then((zone) => { - if (zone === null) { - return Promise.reject( - new Error(`Zone for domain "${domain}" not found.`) - ) - } - return zone - }) - .catch((error) => { - console.warn('WARNING: Request for HostedZone failed!', error.message) - return Promise.resolve('') - }) -} - -const certArn = () => { - const domain = baseDomain() - return getCertArnForDomain(domain) - .then((cert) => { - if (!cert) { - return Promise.reject( - new Error(`Cert for domain "${domain}" not found.`) - ) - } - return cert - }) - .catch((error) => { - console.warn('WARNING: Request for Certificate failed!', error.message) - return Promise.resolve('') - }) + return domain } module.exports = { baseDomain, - bucketSuffix, - certArn, - hostedZone, - stage, } diff --git a/yarn.lock b/yarn.lock index 6b6b1888f..697c863f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14677,11 +14677,6 @@ promise-queue@^2.2.5: resolved "https://registry.yarnpkg.com/promise-queue/-/promise-queue-2.2.5.tgz#2f6f5f7c0f6d08109e967659c79b88a9ed5e93b4" integrity sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ== -promise-timeout@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/promise-timeout/-/promise-timeout-1.3.0.tgz#d1c78dd50a607d5f0a5207410252a3a0914e1014" - integrity sha512-5yANTE0tmi5++POym6OgtFmwfDvOXABD9oj/jLQr5GPEyuNEb7jH4wbbANJceJid49jwhi1RddxnhnEAb/doqg== - promise.allsettled@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.7.tgz#b9dd51e9cffe496243f5271515652c468865f2d8"