diff --git a/.github/workflows/add-terraform-plan-to-pr.yml b/.github/workflows/add-terraform-plan-to-pr.yml index b072931f..818df188 100644 --- a/.github/workflows/add-terraform-plan-to-pr.yml +++ b/.github/workflows/add-terraform-plan-to-pr.yml @@ -3,7 +3,7 @@ name: Post Terraform plan to PR comment on: pull_request: branches: - - staging + - demo - main types: - opened @@ -11,7 +11,7 @@ on: - reopened jobs: - add-terraform-plan-to-staging-pr: + add-terraform-plan-to-demo-pr: uses: ./.github/workflows/_terraform-plan-pr-comment.yml secrets: inherit with: diff --git a/.github/workflows/create-pr-to-staging.yml b/.github/workflows/create-pr-to-staging.yml index d770c25a..c3f15940 100644 --- a/.github/workflows/create-pr-to-staging.yml +++ b/.github/workflows/create-pr-to-staging.yml @@ -1,4 +1,4 @@ -name: Create PR from main to staging +name: Create PR from main to demo on: push: @@ -6,8 +6,8 @@ on: - main jobs: - create-pr-to-staging: + create-pr-to-demo: uses: ./.github/workflows/_pr-create.yml secrets: inherit with: - base: staging + base: demo diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0c8e3e06..a2fefb00 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,7 +4,7 @@ on: push: branches: - main - - staging + - demo workflow_dispatch: jobs: diff --git a/apps/cli/src/cli-controller/secrets.ts b/apps/cli/src/cli-controller/secrets.ts index 3af58398..a7591e33 100644 --- a/apps/cli/src/cli-controller/secrets.ts +++ b/apps/cli/src/cli-controller/secrets.ts @@ -1,3 +1,4 @@ +import { promises as fs } from 'fs'; import path from 'path'; import { Command } from 'commander'; @@ -41,6 +42,17 @@ export const addSecretCommands = (ctx: Context, cli: Command) => { await commands.setSecret(vault, key, value); }); + cmd + .command('set-bulk') + .description('sets secret values from a JSON file') + .argument('', 'Source JSON file for secrets.') + .action(async inputFile => { + const vault = await getSecretsVault(ctx.file); + const maybeJsonString = (await fs.readFile(inputFile)).toString(); + const secrets = JSON.parse(maybeJsonString); + await commands.setSecrets(vault, secrets); + }); + cmd .command('list') .description('list all secret keys') @@ -65,7 +77,7 @@ export const addSecretCommands = (ctx: Context, cli: Command) => { 'generate and save login.gov keypair; if it already exists, it is not ' + 'updated (future work might include adding key rotation)' ) - .argument('', 'deployment environment (dev, staging)') + .argument('', 'deployment environment (dev, demo)') .argument('', 'application key') .action(async (env: DeployEnv, appKey: string) => { const vault = await getSecretsVault(ctx.file); diff --git a/apps/spotlight/src/components/Header.astro b/apps/spotlight/src/components/Header.astro index d073cc86..80d301cb 100644 --- a/apps/spotlight/src/components/Header.astro +++ b/apps/spotlight/src/components/Header.astro @@ -22,7 +22,7 @@ const showAboutContent = false; {!isAboutContent && (
STAGING SERVER - No changes you make here will be visible + >DEMO SERVER - No changes you make here will be visible to the public.
diff --git a/documents/release-process.md b/documents/release-process.md index ca7c1ab3..56a560cb 100644 --- a/documents/release-process.md +++ b/documents/release-process.md @@ -3,12 +3,12 @@ There are currently two environments: - `main` (dev, main branch, CI/CD) -- `staging` (staging branch, merge via release PR) +- `demo` (demo branch, merge via release PR) ## Overview To promote continuous integration, the 10x Forms Platform uses trunk-based development. In trunk-based development, we collaborate in a single, mainline branch. -Deployments are managed by Terraform CDK. On merge to main, the [../.github/workflows/deploy.yml](../.github/workflows/deploy.yml) Github Action workflow builds Docker images for each app in the repository, pushes them to [ghcr.io](https://github.com/orgs/GSA-TTS/packages?repo_name=atj-platform), and deploys to the dev environment (`gsa-tts-10x-atj-dev`). +Deployments are managed by Terraform CDK. On merge to main, the [../.github/workflows/deploy.yml](../.github/workflows/deploy.yml) Github Action workflow builds Docker images for each app in the repository, pushes them to [ghcr.io](https://github.com/orgs/GSA-TTS/packages?repo_name=atj-platform), and deploys to the dev environment (`gsa-tts-10x-forms-dev`). -When commits are made to main, the [../.github/workflows/create-pr-to-staging.yml](../.github/workflows/create-pr-to-staging.yml) workflow creates a PR to merge from `main` to the `staging` branch, if it doesn't already exist. On merge, the staging environment will be deployed. +When commits are made to main, the [../.github/workflows/create-pr-to-demo.yml](../.github/workflows/create-pr-to-demo.yml) workflow creates a PR to merge from `main` to the `demo` branch, if it doesn't already exist. On merge, the demo environment will be deployed. diff --git a/infra/cdktf/package.json b/infra/cdktf/package.json index 14dfadd7..cfc989e5 100644 --- a/infra/cdktf/package.json +++ b/infra/cdktf/package.json @@ -6,14 +6,14 @@ "scripts": { "build": "pnpm build:tsc && pnpm build:synth", "build:get": "cdktf get", - "build:synth": "pnpm build:synth:main && pnpm build:synth:staging", + "build:synth": "pnpm build:synth:main && pnpm build:synth:demo", "build:synth:main": "DEPLOY_ENV=main cdktf synth", - "build:synth:staging": "DEPLOY_ENV=staging cdktf synth", + "build:synth:demo": "DEPLOY_ENV=demo cdktf synth", "build:tsc": "tsc --pretty", "clean": "rimraf cdktf.out dist tsconfig.tsbuildinfo", "clean:gen": "rimraf .gen", "deploy:main": "DEPLOY_ENV=main cdktf deploy", - "deploy:staging": "DEPLOY_ENV=staging cdktf deploy", + "deploy:demo": "DEPLOY_ENV=demo cdktf deploy", "dev": "tsc -w", "test": "jest", "test:watch": "jest --watch" diff --git a/infra/cdktf/scripts/recreate.sh b/infra/cdktf/scripts/recreate.sh index a6679494..4a1da070 100755 --- a/infra/cdktf/scripts/recreate.sh +++ b/infra/cdktf/scripts/recreate.sh @@ -5,7 +5,7 @@ # if it hasn't, do: `pnpm cdktf synth` first. # -pushd cdktf.out/stacks/10x-atj-dev +pushd cdktf.out/stacks/10x-forms-dev terraform taint aws_lightsail_instance.docassemble_lightsail popd pnpm cdktf deploy diff --git a/infra/cdktf/src/index.ts b/infra/cdktf/src/index.ts index 492aeb8e..f7e01283 100644 --- a/infra/cdktf/src/index.ts +++ b/infra/cdktf/src/index.ts @@ -8,8 +8,8 @@ switch (deployEnv) { case 'main': import('./spaces/main'); break; - case 'staging': - import('./spaces/staging'); + case 'demo': + import('./spaces/demo'); break; default: throw new Error(`Please specify a valid environment (got: "${deployEnv}")`); diff --git a/infra/cdktf/src/spaces/staging.ts b/infra/cdktf/src/spaces/demo.ts similarity index 75% rename from infra/cdktf/src/spaces/staging.ts rename to infra/cdktf/src/spaces/demo.ts index ac44cf85..92243e5c 100644 --- a/infra/cdktf/src/spaces/staging.ts +++ b/infra/cdktf/src/spaces/demo.ts @@ -3,4 +3,4 @@ import { execSync } from 'child_process'; import { registerAppStack } from '../lib/app-stack'; const gitCommitHash = execSync('git rev-parse HEAD').toString().trim(); -registerAppStack('tts-10x-atj-staging', gitCommitHash); +registerAppStack('tts-10x-forms-demo', gitCommitHash); diff --git a/infra/cdktf/src/spaces/main.ts b/infra/cdktf/src/spaces/main.ts index 839824f9..d00db808 100644 --- a/infra/cdktf/src/spaces/main.ts +++ b/infra/cdktf/src/spaces/main.ts @@ -3,4 +3,4 @@ import { execSync } from 'child_process'; import { registerAppStack } from '../lib/app-stack'; const gitCommitHash = execSync('git rev-parse HEAD').toString().trim(); -registerAppStack('tts-10x-atj-dev', gitCommitHash); +registerAppStack('tts-10x-forms-dev', gitCommitHash); diff --git a/infra/core/src/commands/index.ts b/infra/core/src/commands/index.ts index c6174b88..5e0d3ae2 100644 --- a/infra/core/src/commands/index.ts +++ b/infra/core/src/commands/index.ts @@ -4,3 +4,4 @@ export { getSecrets } from './get-secrets.js'; export { getSecretKeyList } from './get-secret-key-list.js'; export { setLoginGovSecrets } from './set-login-gov-secrets.js'; export { setSecret } from './set-secret.js'; +export { setSecrets } from './set-secrets.js'; diff --git a/infra/core/src/commands/set-login-gov-secrets.test.ts b/infra/core/src/commands/set-login-gov-secrets.test.ts index 5388e98d..4534336b 100644 --- a/infra/core/src/commands/set-login-gov-secrets.test.ts +++ b/infra/core/src/commands/set-login-gov-secrets.test.ts @@ -30,8 +30,8 @@ describe('set-login-gov-secrets command', () => { expect( await context.vault.getSecrets(await context.vault.getSecretKeys()) ).toEqual({ - [`/tts-10x-atj-dev/${appKey}/login.gov/public-key`]: 'mock public key', - [`/tts-10x-atj-dev/${appKey}/login.gov/private-key`]: 'mock private key', + [`/tts-10x-forms-dev/${appKey}/login.gov/public-key`]: 'mock public key', + [`/tts-10x-forms-dev/${appKey}/login.gov/private-key`]: 'mock private key', }); }); @@ -69,9 +69,9 @@ describe('set-login-gov-secrets command', () => { expect( await context.vault.getSecrets(await context.vault.getSecretKeys()) ).toEqual({ - [`/tts-10x-atj-dev/${appKey}/login.gov/public-key`]: + [`/tts-10x-forms-dev/${appKey}/login.gov/public-key`]: 'mock public key - 1', - [`/tts-10x-atj-dev/${appKey}/login.gov/private-key`]: + [`/tts-10x-forms-dev/${appKey}/login.gov/private-key`]: 'mock private key - 1', }); }); diff --git a/infra/core/src/commands/set-secrets.test.ts b/infra/core/src/commands/set-secrets.test.ts new file mode 100644 index 00000000..c8f10d5d --- /dev/null +++ b/infra/core/src/commands/set-secrets.test.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from 'vitest'; + +import { setSecrets } from './set-secrets.js'; +import { createInMemorySecretsVault } from '../lib/index.js'; + +const getTestVault = (vaultData: any) => { + const result = createInMemorySecretsVault(JSON.stringify(vaultData)); + if (result.success) { + return result.data; + } else { + throw new Error('Error creating in-memory test vault'); + } +}; + +describe('set-secret command', () => { + it('sets secret values', async () => { + const vault = getTestVault({ + 'secret-key-1': 'value-1', + }); + await setSecrets(vault, { + 'secret-key-1': 'secret-value1-updated', + 'secret-key-2': 'secret-value2-updated', + }); + expect(await vault.getSecrets(await vault.getSecretKeys())).toEqual({ + 'secret-key-1': 'secret-value1-updated', + 'secret-key-2': 'secret-value2-updated', + }); + }); +}); diff --git a/infra/core/src/commands/set-secrets.ts b/infra/core/src/commands/set-secrets.ts new file mode 100644 index 00000000..561d3f21 --- /dev/null +++ b/infra/core/src/commands/set-secrets.ts @@ -0,0 +1,13 @@ +import { type SecretsVault } from '../lib/types.js'; + +/** + * Sets a secret in a specified secrets vault. + */ +export const setSecrets = async ( + vault: SecretsVault, + secrets: Record +) => { + for (const key in secrets) { + await vault.setSecret(key, secrets[key]); + } +}; diff --git a/infra/core/src/lib/adapters/aws-param-store.ts b/infra/core/src/lib/adapters/aws-param-store.ts index 12a42cd3..092bcd1f 100644 --- a/infra/core/src/lib/adapters/aws-param-store.ts +++ b/infra/core/src/lib/adapters/aws-param-store.ts @@ -59,26 +59,32 @@ export class AWSParameterStoreSecretsVault implements SecretsVault { } async getSecrets(keys: SecretKey[]) { - try { - const response = await this.client.send( - new GetParametersCommand({ - Names: keys, - WithDecryption: true, - }) - ); - const values: { [key: SecretKey]: SecretValue } = {}; - if (response.Parameters) { - for (const parameter of response.Parameters) { - if (parameter.Name && parameter.Value) { - values[parameter.Name] = parameter.Value; + const chunkSize = 10; + const values: { [key: SecretKey]: SecretValue } = {}; + + for (let i = 0; i < keys.length; i += chunkSize) { + const chunk = keys.slice(i, i + chunkSize); + try { + const response = await this.client.send( + new GetParametersCommand({ + Names: chunk, + WithDecryption: true, + }) + ); + if (response.Parameters) { + for (const parameter of response.Parameters) { + if (parameter.Name && parameter.Value) { + values[parameter.Name] = parameter.Value; + } } } + } catch (error) { + console.error('Error getting parameters:', error); + throw error; } - return values; - } catch (error) { - console.error('Error getting parameters:', error); - throw error; } + + return values; } async setSecret(key: SecretKey, value: SecretValue) { diff --git a/infra/core/src/values.ts b/infra/core/src/values.ts index 7b7730a9..725203e8 100644 --- a/infra/core/src/values.ts +++ b/infra/core/src/values.ts @@ -1,6 +1,6 @@ -export type DeployEnv = 'dev' | 'staging'; +export type DeployEnv = 'dev' | 'demo'; -const getPathPrefix = (env: DeployEnv) => `/tts-10x-atj-${env}`; +const getPathPrefix = (env: DeployEnv) => `/tts-10x-forms-${env}`; /** * Generates an object containing the paths for private/public keys pairs diff --git a/package.json b/package.json index 31cb8f9f..e2f40dbd 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "10x-atj", + "name": "10x-forms", "version": "1.0.0", "description": "Test bed for Access to Justice platform tooling.", "type": "module", diff --git a/packages/database/knexfile.mjs b/packages/database/knexfile.mjs index 86377606..d121cb08 100644 --- a/packages/database/knexfile.mjs +++ b/packages/database/knexfile.mjs @@ -27,7 +27,7 @@ export default { filename: './dev.sqlite3', }, }, - staging: { + demo: { client: 'postgresql', connection: { database: 'my_db', diff --git a/packages/forms/sample-documents/doj-pardon-marijuana/README.md b/packages/forms/sample-documents/doj-pardon-marijuana/README.md index 6b5899e0..7feefc26 100644 --- a/packages/forms/sample-documents/doj-pardon-marijuana/README.md +++ b/packages/forms/sample-documents/doj-pardon-marijuana/README.md @@ -1,4 +1,4 @@ -# 10x-atj sample form - marijuana pardon +# 10x-forms sample form - marijuana pardon Application for Certificate of Pardon for Simple Possession, Attempted Possession, and Use of Marijuana diff --git a/packages/server/src/components/Header.astro b/packages/server/src/components/Header.astro index d0ef689c..7a2b81a9 100644 --- a/packages/server/src/components/Header.astro +++ b/packages/server/src/components/Header.astro @@ -22,8 +22,8 @@ const { session } = getUserSession(Astro);
STAGING SERVER - No changes you make here will be visible - to the public.DEMO SERVER - No changes you make here will be visible to + the public.