Compare commits

..

24 commits

Author SHA1 Message Date
dependabot[bot]
be7533da09
Bump react-native-haptic-feedback from 2.3.4 to 3.0.0 in /mobile
Bumps [react-native-haptic-feedback](https://github.com/mkuczera/react-native-haptic-feedback) from 2.3.4 to 3.0.0.
- [Release notes](https://github.com/mkuczera/react-native-haptic-feedback/releases)
- [Changelog](https://github.com/mkuczera/react-native-haptic-feedback/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkuczera/react-native-haptic-feedback/compare/v2.3.4...v3.0.0)

---
updated-dependencies:
- dependency-name: react-native-haptic-feedback
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-18 22:43:07 +00:00
Adam Moussa
68f77a6c0a Add missing RN CLI deps, exclude mobile from AWS deploy
react-native 0.79 requires @react-native-community/cli as an
explicit dev dependency for CocoaPods autolinking. Also adds
paths-ignore for mobile/ on the AWS deploy workflow so mobile-only
changes don't trigger unnecessary infrastructure deploys.
2026-05-18 18:42:36 -04:00
dependabot[bot]
ed6aed9aa7
Bump react-native from 0.79.7 to 0.85.3 in /mobile (#35)
Bumps [react-native](https://github.com/facebook/react-native/tree/HEAD/packages/react-native) from 0.79.7 to 0.85.3.
- [Release notes](https://github.com/facebook/react-native/releases)
- [Changelog](https://github.com/facebook/react-native/blob/main/CHANGELOG-0.7x.md)
- [Commits](https://github.com/facebook/react-native/commits/v0.85.3/packages/react-native)

---
updated-dependencies:
- dependency-name: react-native
  dependency-version: 0.85.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:40:56 +00:00
Adam Moussa
e64da7ecd7 Revert babel-preset to 0.79 to match React Native version
Dependabot bumped @react-native/babel-preset from 0.79 to 0.85,
which is incompatible with react-native 0.79. The 0.85 preset
expects CLI infrastructure that doesn't exist in 0.79, breaking
pod install during the mobile deploy.
2026-05-18 18:38:03 -04:00
Adam Moussa
e96c80c78a Add OIDC permissions to mobile deploy workflow
Startup failure — caller workflow needs id-token: write for the
reusable workflow's OIDC credential step to function.
2026-05-18 18:35:00 -04:00
Adam Moussa
28475d8529 Revert suggestions log group from foundation stack
The log group already exists — created by the compute stack's
logRetention setting on the suggestions Lambda. Adding it to the
foundation stack caused a duplicate resource error on deploy.
2026-05-18 18:32:04 -04:00
Adam Moussa
fdaaf5ed4a Fix compliance violations: Lambda defaults, CI node-version, dead code
oss-index-creator Lambda was missing functionName, arm64 architecture,
and explicit log retention — all required by the engineering handbook.
CI workflow was not passing node-version to reusable workflows, risking
drift. Removed unused _api_request helper from all four main Lambdas.
Added missing suggestions log group to foundation stack.
2026-05-18 18:28:31 -04:00
dependabot[bot]
69c989847f
Update requests-aws4auth requirement in /lambdas/oss-index-creator (#41)
Updates the requirements on [requests-aws4auth](https://github.com/tedder/requests-aws4auth) to permit the latest version.
- [Release notes](https://github.com/tedder/requests-aws4auth/releases)
- [Changelog](https://github.com/tedder/requests-aws4auth/blob/main/HISTORY.md)
- [Commits](https://github.com/tedder/requests-aws4auth/compare/v1.2.0...v1.3.2)

---
updated-dependencies:
- dependency-name: requests-aws4auth
  dependency-version: 1.3.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:14:39 +00:00
dependabot[bot]
d38049a6ca
Update httpx requirement in /lambdas/suggestions (#46)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:13:16 +00:00
dependabot[bot]
8c692c7477
Update boto3 requirement in /lambdas/pdf-extract (#44)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:28 +00:00
dependabot[bot]
4444eeb678
Update boto3 requirement in /lambdas/pdf-generate (#43)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:20 +00:00
dependabot[bot]
b7ab9ccc9d
Bump @tanstack/react-query from 5.100.10 to 5.100.11 in /web (#42)
Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.100.10 to 5.100.11.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.100.11/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.100.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:14 +00:00
dependabot[bot]
c3a0868d2f
Update boto3 requirement in /lambdas/library-ingest (#45)
Updates the requirements on [boto3](https://github.com/boto/boto3) to permit the latest version.
- [Release notes](https://github.com/boto/boto3/releases)
- [Commits](https://github.com/boto/boto3/compare/1.43.9...1.43.10)

---
updated-dependencies:
- dependency-name: boto3
  dependency-version: 1.43.10
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:12:12 +00:00
Adam Moussa
7dd66caf61 Add missing dependabot entry for lambdas/suggestions 2026-05-18 18:12:02 -04:00
dependabot[bot]
c14d7c2f55
Update requests requirement in /lambdas/oss-index-creator (#40)
Updates the requirements on [requests](https://github.com/psf/requests) to permit the latest version.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.31.0...v2.34.2)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.34.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:11:56 +00:00
dependabot[bot]
d40a58a943
Update opensearch-py requirement in /lambdas/oss-index-creator (#39)
Updates the requirements on [opensearch-py](https://github.com/opensearch-project/opensearch-py) to permit the latest version.
- [Release notes](https://github.com/opensearch-project/opensearch-py/releases)
- [Changelog](https://github.com/opensearch-project/opensearch-py/blob/main/CHANGELOG.md)
- [Commits](https://github.com/opensearch-project/opensearch-py/compare/v2.4.0...v3.2.0)

---
updated-dependencies:
- dependency-name: opensearch-py
  dependency-version: 3.2.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 22:11:54 +00:00
Adam Moussa
ef8a3b5f48 Clean up oss-index-creator: remove debug logging, update docs
- Remove verbose print statements from Lambda handler
- Add dependabot pip entry for oss-index-creator
- Update README with new Lambda and deployed stack state
2026-05-18 18:10:35 -04:00
Adam Moussa
7df81b4427 Fix AOSS dependency ordering: pre-create vector index via Custom Resource
Some checks are pending
Deploy / Deploy to AWS (push) Waiting to run
The Bedrock Knowledge Base creation was failing with 403/404 because
the OpenSearch Serverless data access policy hadn't propagated before
the KB tried to connect. Adds a CDK Custom Resource (using opensearch-py)
that creates the vector index with retry logic, ensuring the full
dependency chain: Collection → DataAccessPolicy → Index → KnowledgeBase.
2026-05-18 17:55:03 -04:00
dependabot[bot]
3250d4d927
Bump Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore from 8.0.11 to 8.0.27 (#37)
---
updated-dependencies:
- dependency-name: Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
  dependency-version: 8.0.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:37:30 +00:00
Adam Moussa
6263551b02 Fix deploy workflow: add permissions for OIDC token
Caller must declare id-token: write for the reusable workflow's
OIDC authentication to function.
2026-05-18 15:32:15 -04:00
dependabot[bot]
7b4a909751
Bump @react-native/babel-preset from 0.79.7 to 0.85.3 in /mobile (#33)
Bumps [@react-native/babel-preset](https://github.com/facebook/react-native) from 0.79.7 to 0.85.3.
- [Release notes](https://github.com/facebook/react-native/releases)
- [Changelog](https://github.com/facebook/react-native/blob/main/CHANGELOG-0.7x.md)
- [Commits](https://github.com/facebook/react-native/compare/v0.79.7...v0.85.3)

---
updated-dependencies:
- dependency-name: "@react-native/babel-preset"
  dependency-version: 0.85.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:32:13 +00:00
dependabot[bot]
cc7dfa3d07
Update httpx requirement in /lambdas/pdf-generate (#32)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:32:05 +00:00
dependabot[bot]
9994be3fed
Update httpx requirement in /lambdas/pdf-extract (#28)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:31:56 +00:00
dependabot[bot]
923b6a4712
Update httpx requirement in /lambdas/library-ingest (#25)
Updates the requirements on [httpx](https://github.com/encode/httpx) to permit the latest version.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.27.0...0.28.1)

---
updated-dependencies:
- dependency-name: httpx
  dependency-version: 0.28.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-18 19:31:41 +00:00
21 changed files with 2982 additions and 991 deletions

View file

@ -56,6 +56,20 @@ updates:
open-pull-requests-limit: 3 open-pull-requests-limit: 3
- package-ecosystem: pip
directory: /lambdas/suggestions
schedule:
interval: weekly
open-pull-requests-limit: 3
- package-ecosystem: pip
directory: /lambdas/oss-index-creator
schedule:
interval: weekly
open-pull-requests-limit: 3
- package-ecosystem: github-actions - package-ecosystem: github-actions
directory: / directory: /
schedule: schedule:

View file

@ -21,6 +21,7 @@ jobs:
with: with:
working-directory: web working-directory: web
cache-dependency-path: web/package-lock.json cache-dependency-path: web/package-lock.json
node-version: "24"
run-cdk-synth: false run-cdk-synth: false
run-conventions-check: false run-conventions-check: false
@ -38,6 +39,7 @@ jobs:
with: with:
working-directory: mobile working-directory: mobile
cache-dependency-path: mobile/package-lock.json cache-dependency-path: mobile/package-lock.json
node-version: "24"
run-cdk-synth: false run-cdk-synth: false
run-conventions-check: false run-conventions-check: false
@ -47,6 +49,7 @@ jobs:
with: with:
working-directory: infra working-directory: infra
cache-dependency-path: infra/package-lock.json cache-dependency-path: infra/package-lock.json
node-version: "24"
dotnet-version: "8.0.x" dotnet-version: "8.0.x"
dotnet-publish-project: api/src/ProposalSystem.Api/ProposalSystem.Api.csproj dotnet-publish-project: api/src/ProposalSystem.Api/ProposalSystem.Api.csproj
run-typecheck: false run-typecheck: false

View file

@ -12,6 +12,10 @@ concurrency:
group: deploy-mobile group: deploy-mobile
cancel-in-progress: false cancel-in-progress: false
permissions:
id-token: write
contents: read
jobs: jobs:
deploy-ios: deploy-ios:
name: Build & Upload to TestFlight name: Build & Upload to TestFlight

View file

@ -3,11 +3,17 @@ name: Deploy
on: on:
push: push:
branches: [main] branches: [main]
paths-ignore:
- "mobile/**"
concurrency: concurrency:
group: deploy-backend group: deploy-backend
cancel-in-progress: false cancel-in-progress: false
permissions:
id-token: write
contents: read
jobs: jobs:
deploy: deploy:
name: Deploy to AWS name: Deploy to AWS

View file

@ -9,7 +9,7 @@ Monorepo with five primary services:
- **.NET 8 API** -- Clean Architecture REST API hosted on Lambda behind API Gateway - **.NET 8 API** -- Clean Architecture REST API hosted on Lambda behind API Gateway
- **React 19 Web** -- MUI v7 admin/dispatcher workspace served via CloudFront + S3 - **React 19 Web** -- MUI v7 admin/dispatcher workspace served via CloudFront + S3
- **React Native Mobile** -- iOS-first field app for dispatchers (offline-capable) - **React Native Mobile** -- iOS-first field app for dispatchers (offline-capable)
- **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions - **Python Lambdas** -- PDF extraction, PDF generation, library ingestion, AI suggestions, AOSS index provisioning
- **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources - **CDK Infrastructure** -- Three TypeScript stacks managing all AWS resources
## Repository Structure ## Repository Structure
@ -41,12 +41,12 @@ proposal-system/
## AWS Resources ## AWS Resources
All resources are in **us-east-1** (account 328440206208). CDK stacks are defined but not yet deployed to AWS. All resources are in **us-east-1** (account 328440206208).
| CDK Stack | Key Resources | | CDK Stack | Key Resources |
|---|---| |---|---|
| `proposal-system-foundation` | RDS PostgreSQL 15 (t4g.small), S3 buckets, SQS queue + DLQ, Cognito user pool, Secrets Manager | | `proposal-system-foundation` | RDS PostgreSQL 15 (t4g.small), S3 buckets, SQS queue + DLQ, Cognito user pool, Secrets Manager |
| `proposal-system-compute` | API Gateway HTTP API, .NET 8 API Lambda, Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions), Bedrock KB | | `proposal-system-compute` | API Gateway HTTP API, .NET 8 API Lambda, Python Lambdas (pdf-extract, pdf-generate, library-ingest, suggestions, oss-index-creator), OpenSearch Serverless collection, Bedrock KB |
| `proposal-system-frontend` | CloudFront distribution (S3 OAC) | | `proposal-system-frontend` | CloudFront distribution (S3 OAC) |
| Resource Type | Names | | Resource Type | Names |

View file

@ -21,7 +21,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.27" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.27" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.1" /> <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.11" /> <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.27" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -12,6 +12,7 @@ import * as lambdaEventSources from 'aws-cdk-lib/aws-lambda-event-sources';
import * as bedrock from 'aws-cdk-lib/aws-bedrock'; import * as bedrock from 'aws-cdk-lib/aws-bedrock';
import * as opensearchserverless from 'aws-cdk-lib/aws-opensearchserverless'; import * as opensearchserverless from 'aws-cdk-lib/aws-opensearchserverless';
import * as logs from 'aws-cdk-lib/aws-logs'; import * as logs from 'aws-cdk-lib/aws-logs';
import * as cr from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs'; import { Construct } from 'constructs';
export interface ComputeStackProps extends cdk.StackProps { export interface ComputeStackProps extends cdk.StackProps {
@ -90,8 +91,31 @@ export class ComputeStack extends cdk.Stack {
resources: [`arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0`], resources: [`arn:aws:bedrock:us-east-1::foundation-model/amazon.titan-embed-text-v2:0`],
})); }));
// OpenSearch Serverless data access policy // Lambda to pre-create the vector index (retries until AOSS access policy propagates)
new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', { const indexCreatorFn = new lambda.Function(this, 'OssIndexCreator', {
functionName: 'proposal-system-oss-index-creator',
runtime: lambda.Runtime.PYTHON_3_12,
architecture: lambda.Architecture.ARM_64,
handler: 'app.handler',
code: lambda.Code.fromAsset('../lambdas/oss-index-creator', {
bundling: {
image: lambda.Runtime.PYTHON_3_12.bundlingImage,
command: [
'bash', '-c',
'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output',
],
},
}),
timeout: cdk.Duration.minutes(6),
logRetention: logs.RetentionDays.TWO_MONTHS,
});
indexCreatorFn.addToRolePolicy(new iam.PolicyStatement({
actions: ['aoss:APIAccessAll'],
resources: [ossCollection.attrArn],
}));
const ossDataAccessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', {
name: 'proposal-system-kb-access', name: 'proposal-system-kb-access',
type: 'data', type: 'data',
policy: JSON.stringify([{ policy: JSON.stringify([{
@ -99,11 +123,27 @@ export class ComputeStack extends cdk.Stack {
{ ResourceType: 'collection', Resource: ['collection/proposal-system-kb'], Permission: ['aoss:*'] }, { ResourceType: 'collection', Resource: ['collection/proposal-system-kb'], Permission: ['aoss:*'] },
{ ResourceType: 'index', Resource: ['index/proposal-system-kb/*'], Permission: ['aoss:*'] }, { ResourceType: 'index', Resource: ['index/proposal-system-kb/*'], Permission: ['aoss:*'] },
], ],
Principal: [kbRole.roleArn, `arn:aws:iam::${this.account}:root`], Principal: [kbRole.roleArn, indexCreatorFn.role!.roleArn],
}]), }]),
}); });
ossDataAccessPolicy.addDependency(ossCollection);
const indexProvider = new cr.Provider(this, 'OssIndexProvider', {
onEventHandler: indexCreatorFn,
});
const ossIndex = new cdk.CustomResource(this, 'OssIndex', {
serviceToken: indexProvider.serviceToken,
properties: {
Endpoint: ossCollection.attrCollectionEndpoint,
IndexName: 'proposal-system-index',
VectorField: 'embedding',
TextField: 'text',
MetadataField: 'metadata',
},
});
ossIndex.node.addDependency(ossDataAccessPolicy);
// Bedrock Knowledge Base
const knowledgeBase = new bedrock.CfnKnowledgeBase(this, 'KnowledgeBase', { const knowledgeBase = new bedrock.CfnKnowledgeBase(this, 'KnowledgeBase', {
name: 'proposal-system-kb', name: 'proposal-system-kb',
roleArn: kbRole.roleArn, roleArn: kbRole.roleArn,
@ -126,6 +166,7 @@ export class ComputeStack extends cdk.Stack {
}, },
}, },
}); });
knowledgeBase.node.addDependency(ossIndex);
// KB Data Source (S3 library bucket) // KB Data Source (S3 library bucket)
const dataSource = new bedrock.CfnDataSource(this, 'KbDataSource', { const dataSource = new bedrock.CfnDataSource(this, 'KbDataSource', {

View file

@ -8,7 +8,6 @@ then triggers a KB sync.
import json import json
import logging import logging
import os import os
import time
from datetime import datetime from datetime import datetime
import boto3 import boto3
@ -199,27 +198,3 @@ def _api_headers() -> dict:
if api_key: if api_key:
headers["X-Internal-Api-Key"] = api_key headers["X-Internal-Api-Key"] = api_key
return headers return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,2 +1,2 @@
boto3>=1.43.9,<2.0 boto3>=1.43.10,<2.0
httpx>=0.27.0,<1.0 httpx>=0.28.1,<1.0

View file

@ -0,0 +1,71 @@
import time
import boto3
from opensearchpy import OpenSearch, RequestsHttpConnection
from requests_aws4auth import AWS4Auth
def handler(event, context):
if event["RequestType"] == "Delete":
return {"PhysicalResourceId": event.get("PhysicalResourceId", "none")}
props = event["ResourceProperties"]
endpoint = props["Endpoint"].replace("https://", "")
index_name = props["IndexName"]
vector_field = props["VectorField"]
text_field = props["TextField"]
metadata_field = props["MetadataField"]
session = boto3.Session()
credentials = session.get_credentials().get_frozen_credentials()
region = session.region_name
awsauth = AWS4Auth(
credentials.access_key,
credentials.secret_key,
region,
"aoss",
session_token=credentials.token,
)
client = OpenSearch(
hosts=[{"host": endpoint, "port": 443}],
http_auth=awsauth,
use_ssl=True,
verify_certs=True,
connection_class=RequestsHttpConnection,
timeout=30,
)
index_body = {
"settings": {"index": {"knn": True, "knn.algo_param.ef_search": 512}},
"mappings": {
"properties": {
vector_field: {
"type": "knn_vector",
"dimension": 1024,
"method": {
"engine": "faiss",
"name": "hnsw",
"space_type": "l2",
},
},
text_field: {"type": "text"},
metadata_field: {"type": "text"},
}
},
}
for attempt in range(30):
try:
client.indices.create(index=index_name, body=index_body)
return {"PhysicalResourceId": index_name}
except Exception as e:
error_str = str(e)
if "resource_already_exists_exception" in error_str:
return {"PhysicalResourceId": index_name}
if "403" in error_str and attempt < 29:
time.sleep(10)
continue
raise
raise Exception("Timeout waiting for AOSS access policy propagation")

View file

@ -0,0 +1,3 @@
opensearch-py>=3.2.0
requests-aws4auth>=1.3.2
requests>=2.34.2

View file

@ -9,7 +9,6 @@ import json
import logging import logging
import os import os
import tempfile import tempfile
import time
import boto3 import boto3
import httpx import httpx
@ -339,27 +338,3 @@ def _api_headers() -> dict:
if api_key: if api_key:
headers["X-Internal-Api-Key"] = api_key headers["X-Internal-Api-Key"] = api_key
return headers return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,3 +1,3 @@
pdfplumber>=0.11.9,<1.0 pdfplumber>=0.11.9,<1.0
boto3>=1.43.9,<2.0 boto3>=1.43.10,<2.0
httpx>=0.27.0,<1.0 httpx>=0.28.1,<1.0

View file

@ -7,7 +7,6 @@ Triggered via SQS when an admin requests PDF generation.
import json import json
import logging import logging
import os import os
import time
from datetime import datetime from datetime import datetime
from io import BytesIO from io import BytesIO
@ -543,27 +542,3 @@ def _api_headers() -> dict:
if api_key: if api_key:
headers["X-Internal-Api-Key"] = api_key headers["X-Internal-Api-Key"] = api_key
return headers return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,3 +1,3 @@
reportlab>=4.5.1,<5.0 reportlab>=4.5.1,<5.0
boto3>=1.43.9,<2.0 boto3>=1.43.10,<2.0
httpx>=0.27.0,<1.0 httpx>=0.28.1,<1.0

View file

@ -7,7 +7,6 @@ to generate line item suggestions for new proposals.
import json import json
import logging import logging
import os import os
import time
import boto3 import boto3
import httpx import httpx
@ -320,27 +319,3 @@ def _api_headers() -> dict:
if api_key: if api_key:
headers["X-Internal-Api-Key"] = api_key headers["X-Internal-Api-Key"] = api_key
return headers return headers
def _api_request(method: str, url: str, retries: int = 3, **kwargs) -> httpx.Response:
kwargs.setdefault("headers", _api_headers())
kwargs.setdefault("timeout", 10)
for attempt in range(retries):
try:
resp = httpx.request(method, url, **kwargs)
if resp.status_code < 500:
return resp
logger.warning(
"API returned %s on attempt %d for %s",
resp.status_code,
attempt + 1,
url,
)
except httpx.TransportError as e:
logger.warning(
"Transport error on attempt %d for %s: %s", attempt + 1, url, e
)
if attempt == retries - 1:
raise
time.sleep(min(2**attempt, 4))
return resp # type: ignore[possibly-undefined]

View file

@ -1,2 +1,2 @@
boto3>=1.35.0,<2.0 boto3>=1.35.0,<2.0
httpx>=0.27.0,<1.0 httpx>=0.28.1,<1.0

3624
mobile/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@
"@tanstack/react-query": "^5.100.10", "@tanstack/react-query": "^5.100.10",
"axios": "^1.16.0", "axios": "^1.16.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-native": "^0.79.0", "react-native": "^0.85.3",
"react-native-app-auth": "^8.0.0", "react-native-app-auth": "^8.0.0",
"react-native-document-picker": "^9.3.0", "react-native-document-picker": "^9.3.0",
"react-native-haptic-feedback": "^3.0.0", "react-native-haptic-feedback": "^3.0.0",
@ -33,6 +33,8 @@
"react-redux": "^9.2.0" "react-redux": "^9.2.0"
}, },
"devDependencies": { "devDependencies": {
"@react-native-community/cli": "^20.1.3",
"@react-native-community/cli-platform-ios": "^20.1.3",
"@react-native/babel-preset": "^0.79.0", "@react-native/babel-preset": "^0.79.0",
"@react-native/metro-config": "^0.79.0", "@react-native/metro-config": "^0.79.0",
"@types/react": "^19.0.0", "@types/react": "^19.0.0",

71
web/package-lock.json generated
View file

@ -13,7 +13,7 @@
"@mui/icons-material": "^7.3.1", "@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1", "@mui/material": "^7.3.1",
"@reduxjs/toolkit": "^2.11.2", "@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.100.10", "@tanstack/react-query": "^5.100.11",
"axios": "^1.16.0", "axios": "^1.16.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
@ -1319,9 +1319,6 @@
"arm" "arm"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1336,9 +1333,6 @@
"arm" "arm"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1353,9 +1347,6 @@
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1370,9 +1361,6 @@
"arm64" "arm64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1387,9 +1375,6 @@
"loong64" "loong64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1404,9 +1389,6 @@
"loong64" "loong64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1421,9 +1403,6 @@
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1438,9 +1417,6 @@
"ppc64" "ppc64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1455,9 +1431,6 @@
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1472,9 +1445,6 @@
"riscv64" "riscv64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1489,9 +1459,6 @@
"s390x" "s390x"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1506,9 +1473,6 @@
"x64" "x64"
], ],
"dev": true, "dev": true,
"libc": [
"glibc"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1523,9 +1487,6 @@
"x64" "x64"
], ],
"dev": true, "dev": true,
"libc": [
"musl"
],
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
"os": [ "os": [
@ -1629,9 +1590,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tanstack/query-core": { "node_modules/@tanstack/query-core": {
"version": "5.100.10", "version": "5.100.11",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.10.tgz", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.11.tgz",
"integrity": "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==", "integrity": "sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw==",
"license": "MIT", "license": "MIT",
"funding": { "funding": {
"type": "github", "type": "github",
@ -1639,12 +1600,12 @@
} }
}, },
"node_modules/@tanstack/react-query": { "node_modules/@tanstack/react-query": {
"version": "5.100.10", "version": "5.100.11",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.10.tgz", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.11.tgz",
"integrity": "sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==", "integrity": "sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tanstack/query-core": "5.100.10" "@tanstack/query-core": "5.100.11"
}, },
"funding": { "funding": {
"type": "github", "type": "github",
@ -3100,22 +3061,6 @@
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
},
"node_modules/yaml": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
"extraneous": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
} }
} }
} }

View file

@ -14,7 +14,7 @@
"@mui/icons-material": "^7.3.1", "@mui/icons-material": "^7.3.1",
"@mui/material": "^7.3.1", "@mui/material": "^7.3.1",
"@reduxjs/toolkit": "^2.11.2", "@reduxjs/toolkit": "^2.11.2",
"@tanstack/react-query": "^5.100.10", "@tanstack/react-query": "^5.100.11",
"axios": "^1.16.0", "axios": "^1.16.0",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",