Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions apps/cli/src/cli-controller/secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import { promises as fs } from 'fs';
import path from 'path';
import { Command } from 'commander';

import {
type DeployEnv,
commands,
getSecretsVault,
} from '@flexion/forms-infra-core';
import { commands, getSecretsVault } from '@flexion/forms-infra-core';
import { type Context } from './types.js';

export const addSecretCommands = (ctx: Context, cli: Command) => {
Expand Down Expand Up @@ -79,17 +75,20 @@ export const addSecretCommands = (ctx: Context, cli: Command) => {
.command('set-login-gov-keys')
.description(
'generate and save login.gov keypair; if it already exists, it is not ' +
'updated (future work might include adding key rotation)',
'updated (future work might include adding key rotation)'
)
.argument('<deploy-env>', 'deployment environment (dev, demo)')
.argument('<app-key>', 'application key')
.action(async (env: DeployEnv, appKey: string) => {
.argument(
'<root-key>',
'root key for secrets (e.g., flexion-forms-demo, tts-10x-forms-dev)'
)
.argument('<app-key>', 'application key (e.g., server-doj, server-kansas)')
.action(async (rootKey: string, appKey: string) => {
const vault = await getSecretsVault(ctx.file);
const secretsDir = path.resolve(__dirname, '../../../infra/secrets');
const loginResult = await commands.setLoginGovSecrets(
{ vault, secretsDir },
env,
appKey,
rootKey,
appKey
);
if (loginResult.preexisting) {
console.log('Keypair already exists.');
Expand Down
2 changes: 1 addition & 1 deletion apps/sandbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"build": "tsup src/* --format esm",
"clean": "rimraf dist tsconfig.tsbuildinfo coverage",
"dev": "tsup src/* --watch --format esm",
"start": "VCAP_SERVICES='{\"aws-rds\": [{ \"credentials\": { \"uri\": \"\" }}]}' node dist/index.js",
"start": "node dist/index.js",
"test": "vitest run --coverage"
},
"dependencies": {
Expand Down
18 changes: 5 additions & 13 deletions apps/sandbox/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,16 @@ import { createCustomServer } from './server.js';

const port = process.env.PORT || 4321;

const getCloudGovServerSecrets = () => {
if (process.env.VCAP_SERVICES === undefined) {
return;
}
const services = JSON.parse(process.env.VCAP_SERVICES || '{}');
return {
//loginGovClientSecret: services['user-provided']?.credentials?.SECRET_LOGIN_GOV_PRIVATE_KEY,
dbUri: services['aws-rds'][0].credentials.uri as string,
};
};

const getAppRunnerSecrets = async () => {
const dbSecretArn = process.env.DB_SECRET_ARN;
const dbHost = process.env.DB_HOST;
const dbPort = process.env.DB_PORT;
const dbName = process.env.DB_NAME;

if (!dbSecretArn || !dbHost || !dbPort || !dbName) {
console.error(
'Missing required environment variables: DB_SECRET_ARN, DB_HOST, DB_PORT, DB_NAME'
);
return;
}

Expand All @@ -35,11 +27,11 @@ const getAppRunnerSecrets = async () => {

const dbSecret = JSON.parse(dbSecretString);
return {
dbUri: `postgresql://${dbSecret.username}:${dbSecret.password}@${dbHost}:${dbPort}/${dbName}`
dbUri: `postgresql://${dbSecret.username}:${dbSecret.password}@${dbHost}:${dbPort}/${dbName}`,
};
};

const secrets = getCloudGovServerSecrets() || (await getAppRunnerSecrets());
const secrets = await getAppRunnerSecrets();
if (secrets === undefined) {
console.error('Error getting secrets');
process.exit(1);
Expand Down
2 changes: 1 addition & 1 deletion infra/cdktf/src/spaces/aws/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AwsDemoStack extends TerraformStack {

// Create the sandbox infrastructure
new SandboxStack(this, stackName, {
environment: 'demo-aws',
environment: 'flexion-forms-demo',
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion infra/cdktf/src/spaces/aws/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AwsMainStack extends TerraformStack {

// Create the sandbox infrastructure
new SandboxStack(this, stackName, {
environment: 'main-aws',
environment: 'flexion-forms-main',
});
}
}
Expand Down
19 changes: 12 additions & 7 deletions infra/core/src/commands/set-login-gov-secrets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ describe('set-login-gov-secrets command', () => {
}),
};
const appKey = randomUUID();
const result = await setLoginGovSecrets(context, 'dev', appKey);
const result = await setLoginGovSecrets(
context,
'flexion-forms-dev',
appKey
);
expect(result.preexisting).toEqual(false);
expect(
await context.vault.getSecrets(await context.vault.getSecretKeys())
).toEqual({
[`/tts-10x-forms-dev/${appKey}/login.gov/public-key`]: 'mock public key',
[`/tts-10x-forms-dev/${appKey}/login.gov/private-key`]: 'mock private key',
[`/flexion-forms-dev/${appKey}/login.gov/public-key`]: 'mock public key',
[`/flexion-forms-dev/${appKey}/login.gov/private-key`]:
'mock private key',
});
});

Expand All @@ -50,7 +55,7 @@ describe('set-login-gov-secrets command', () => {
privateKey: 'mock private key - 1',
}),
},
'dev',
'flexion-forms-dev',
appKey
);
const secondResult = await setLoginGovSecrets(
Expand All @@ -61,17 +66,17 @@ describe('set-login-gov-secrets command', () => {
privateKey: 'mock private key - 2',
}),
},
'dev',
'flexion-forms-dev',
appKey
);

expect(secondResult.preexisting).toEqual(true);
expect(
await context.vault.getSecrets(await context.vault.getSecretKeys())
).toEqual({
[`/tts-10x-forms-dev/${appKey}/login.gov/public-key`]:
[`/flexion-forms-dev/${appKey}/login.gov/public-key`]:
'mock public key - 1',
[`/tts-10x-forms-dev/${appKey}/login.gov/private-key`]:
[`/flexion-forms-dev/${appKey}/login.gov/private-key`]:
'mock private key - 1',
});
});
Expand Down
10 changes: 7 additions & 3 deletions infra/core/src/commands/set-login-gov-secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { promises as fs } from 'fs';
import { promisify } from 'util';

import { type SecretsVault } from '../lib/types.js';
import { type DeployEnv, getAppLoginGovKeys } from '../values.js';
import { getAppLoginGovKeys } from '../values.js';

const execPromise = promisify(exec);

Expand All @@ -24,13 +24,17 @@ type Context = {
/**
* Sets or retrieves Login.gov secrets for the given application key. It retrieves and returns the
* existing key pair or generates, stores, and returns new key pair if one didn't exist previously.
*
* @param ctx Context with vault and secrets directory
* @param rootKey The root key for secrets (e.g., 'flexion-forms-demo', 'tts-10x-forms-dev')
* @param appKey The application key (e.g., 'server-doj', 'server-kansas')
*/
export const setLoginGovSecrets = async (
ctx: Context,
env: DeployEnv,
rootKey: string,
appKey: string
) => {
const loginKeys = getAppLoginGovKeys(env, appKey);
const loginKeys = getAppLoginGovKeys(rootKey, appKey);

// If the keypair is already set, do nothing and return it.
const existingPublicKey = await ctx.vault.getSecret(loginKeys.publicKey);
Expand Down
1 change: 1 addition & 0 deletions infra/core/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type SecretMap, type SecretsVault } from './types.js';

export { getSecretMapFromJsonString } from './types.js';
export * from './adapters/index.js';
export * from './secrets/index.js';

export const getSecretMap = async (vault: SecretsVault): Promise<SecretMap> => {
const secretKeys = await vault.getSecretKeys();
Expand Down
24 changes: 11 additions & 13 deletions infra/core/src/lib/secrets/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
export const getSecretKeys = (env: string) => [
`/tts-10x-forms-${env}/cloudfoundry/password`,
`/tts-10x-forms-${env}/cloudfoundry/username`,
`/tts-10x-forms-${env}/server-doj/leidos-intranet-quorum/password`,
`/tts-10x-forms-${env}/server-doj/leidos-intranet-quorum/username`,
`/tts-10x-forms-${env}/server-doj/login.gov/private-key`,
`/tts-10x-forms-${env}/server-doj/login.gov/public-key`,
`/tts-10x-forms-${env}/server-kansas/login.gov/private-key`,
`/tts-10x-forms-${env}/server-kansas/login.gov/public-key`,
export const getSecretKeys = (rootKey: string) => [
`/${rootKey}/cloudfoundry/password`,
`/${rootKey}/cloudfoundry/username`,
`/${rootKey}/server-doj/leidos-intranet-quorum/password`,
`/${rootKey}/server-doj/leidos-intranet-quorum/username`,
`/${rootKey}/server-doj/login.gov/private-key`,
`/${rootKey}/server-doj/login.gov/public-key`,
`/${rootKey}/server-kansas/login.gov/private-key`,
`/${rootKey}/server-kansas/login.gov/public-key`,
`/${rootKey}/database`,
];

const secretPrefix = (env: string) => `/tts-10x-forms-${env}`;

export const getDatabaseSecretKey = (env: string) =>
`${secretPrefix(env)}/database`;
export const getDatabaseSecretKey = (rootKey: string) => `/${rootKey}/database`;
12 changes: 6 additions & 6 deletions infra/core/src/values.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
export type DeployEnv = 'dev' | 'demo';

const getPathPrefix = (env: DeployEnv) => `/tts-10x-forms-${env}`;

/**
* Generates an object containing the paths for private/public keys pairs
* associated with login.gov for an application in the specified
* deployment environment.
*
* @param rootKey The root key for secrets (e.g., 'flexion-forms-demo', 'tts-10x-forms-dev')
* @param appKey The application key (e.g., 'server-doj', 'server-kansas')
*/
export const getAppLoginGovKeys = (env: DeployEnv, appKey: string) => {
const prefix = getPathPrefix(env);
export const getAppLoginGovKeys = (rootKey: string, appKey: string) => {
return {
privateKey: `${prefix}/${appKey}/login.gov/private-key`,
publicKey: `${prefix}/${appKey}/login.gov/public-key`,
privateKey: `/${rootKey}/${appKey}/login.gov/private-key`,
publicKey: `/${rootKey}/${appKey}/login.gov/public-key`,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ describe('DOJ Pardon Attorney Office - Marijuana pardon application form', () =>
const { createTestPdfParser } = await import('../pdf/index.js');
const { defaultFormConfig } = await import('../../patterns/index.js');
const parser = createTestPdfParser();
const result = await parsePdf({ parser, formConfig: defaultFormConfig }, pdfBytes);
const result = await parsePdf(
{ parser, formConfig: defaultFormConfig },
pdfBytes
);
const { parsedPdf, fields } = result;

// Should create valid pattern structure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
type BedrockConfig,
} from '../../../llm/providers/bedrock.js';


/**
* System prompt for the LLM
*/
Expand Down
8 changes: 6 additions & 2 deletions packages/forms/src/llm/cache/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ export const computeObjectCacheKey = async (
const keyComponents = {
model: extractModelId(params.model),
system: 'system' in params ? params.system : undefined,
messages: 'messages' in params ? await hashMessages(params.messages ?? []) : undefined,
messages:
'messages' in params
? await hashMessages(params.messages ?? [])
: undefined,
schema: 'schema' in params ? await hashSchema(params.schema) : undefined,
schemaName: 'schemaName' in params ? params.schemaName : undefined,
schemaDescription: 'schemaDescription' in params ? params.schemaDescription : undefined,
schemaDescription:
'schemaDescription' in params ? params.schemaDescription : undefined,
temperature: 'temperature' in params ? params.temperature : undefined,
topP: 'topP' in params ? params.topP : undefined,
maxTokens: 'maxTokens' in params ? params.maxTokens : undefined,
Expand Down
7 changes: 4 additions & 3 deletions packages/forms/src/llm/services/generate-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export const generateObjectCached = async <T extends ZodType>(
const cacheKey = await computeObjectCacheKey(params);

// Try cache first
const cached = await context.cache.get<
Awaited<ReturnType<typeof generateObject<T>>>
>(cacheKey);
const cached =
await context.cache.get<Awaited<ReturnType<typeof generateObject<T>>>>(
cacheKey
);

if (cached) {
console.log('[LLM Cache] Hit:', cacheKey.slice(0, 16));
Expand Down
5 changes: 4 additions & 1 deletion packages/forms/src/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { type ServiceMethod, createService } from '@flexion/forms-common';

import { type FormServiceContext, type InternalFormServiceContext } from '../context/index.js';
import {
type FormServiceContext,
type InternalFormServiceContext,
} from '../context/index.js';
import { parsePdf as parsePdfCore } from '../documents/pdf/parsing-api.js';

import { type AddForm, addForm } from './add-form.js';
Expand Down
Loading