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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
24 changes: 12 additions & 12 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
**/__pycache__

# Only the four packaged service JARs enter application build contexts.
!payguard-identity-service/target/
payguard-identity-service/target/*
!payguard-identity-service/target/payguard-identity-service-1.0.0-SNAPSHOT.jar
!payguard-wallet-service/target/
payguard-wallet-service/target/*
!payguard-wallet-service/target/payguard-wallet-service-1.0.0-SNAPSHOT.jar
!payguard-loan-service/target/
payguard-loan-service/target/*
!payguard-loan-service/target/payguard-loan-service-1.0.0-SNAPSHOT.jar
!payguard-collateral-service/target/
payguard-collateral-service/target/*
!payguard-collateral-service/target/payguard-collateral-service-1.0.0-SNAPSHOT.jar
!payguard-identity/target/
payguard-identity/target/*
!payguard-identity/target/payguard-identity-1.0.0-SNAPSHOT.jar
!payguard-wallet/target/
payguard-wallet/target/*
!payguard-wallet/target/payguard-wallet-1.0.0-SNAPSHOT.jar
!payguard-loan/target/
payguard-loan/target/*
!payguard-loan/target/payguard-loan-1.0.0-SNAPSHOT.jar
!payguard-collateral/target/
payguard-collateral/target/*
!payguard-collateral/target/payguard-collateral-1.0.0-SNAPSHOT.jar
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ PAYGUARD_POSTGRES_COLLATERAL_VOLUME=payguard_postgres_collateral_data
PAYGUARD_VAULT_DATA_VOLUME=payguard_vault_data
PAYGUARD_VAULT_AUDIT_VOLUME=payguard_vault_audit
PAYGUARD_KAFKA_DATA_VOLUME=payguard_kafka_data

# Optional localhost ports with infrastructure/compose.ide.yaml.
WALLET_POSTGRES_PORT=15431
LOAN_POSTGRES_PORT=15432
COLLATERAL_POSTGRES_PORT=15433
IDENTITY_POSTGRES_PORT=15434
2 changes: 1 addition & 1 deletion .github/workflows/_database-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
- name: Verify source contracts and build applications
run: |
python3 -m unittest discover -s infrastructure/tests -v
./mvnw -B -ntp -pl payguard-identity-service,payguard-wallet-service,payguard-loan-service,payguard-collateral-service -am test package
./mvnw -B -ntp -pl payguard-identity,payguard-wallet,payguard-loan,payguard-collateral -am test package
- name: Prepare isolated fixture and allocate only new explicit volumes
run: |
ansible-playbook -i localhost, -c local infrastructure/operations/prepare.yml -e fresh_target=true
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ jobs:
- name: Verify Spring Boot plugin resolution
run: |
./mvnw -version
./mvnw help:effective-pom -pl payguard-wallet-service \
./mvnw help:effective-pom -pl payguard-wallet \
| grep -A8 -B2 spring-boot-maven-plugin

- name: Build Wallet Service Image
run: docker build -f payguard-wallet-service/Dockerfile -t payguard/wallet-service:${{ github.sha }} .
run: docker build -f payguard-wallet/Dockerfile -t payguard/wallet-service:${{ github.sha }} .

- name: Build Loan Service Image
run: docker build -f payguard-loan-service/Dockerfile -t payguard/loan-service:${{ github.sha }} .
run: docker build -f payguard-loan/Dockerfile -t payguard/loan-service:${{ github.sha }} .

- name: Build Collateral Service Image
run: docker build -f payguard-collateral-service/Dockerfile -t payguard/collateral-service:${{ github.sha }} .
run: docker build -f payguard-collateral/Dockerfile -t payguard/collateral-service:${{ github.sha }} .

- name: Build Identity Service Image
run: docker build -f payguard-identity-service/Dockerfile -t payguard/identity-service:${{ github.sha }} .
run: docker build -f payguard-identity/Dockerfile -t payguard/identity-service:${{ github.sha }} .
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ PAYGUARD_GOAL.md
# Protected local PostgreSQL/Vault rehearsal artifacts
.local/
__pycache__/

CLAUDE.md
payguard-identity/NEW IDEAS.MD
payguard-identity/ARCHITECTURE.md
payguard-identity/IDENTITY_CHECKLIST.MD
NO_LLM_FOR_CODING.MD
301 changes: 226 additions & 75 deletions README.md

Large diffs are not rendered by default.

This file was deleted.

79 changes: 10 additions & 69 deletions docs/infrastructure-validation.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,13 @@
# Vault and native infrastructure validation
# Validation after restoring stashed work

This branch is based on `main` at `c904d71ef8a7541885cbbe887f25148e196ef768`.
It contains the infrastructure replacement, adapted to the committed service module names.
The owner's uncommitted module renames, Identity refactor, Wallet edits, and local tooling
remain outside the branch. No live database, Vault state, or deployment was accessed.
Current source and evidence are documented in [the recovery record](recovery/stashed-work.md).

## Scope
The recovered reactor packages and compiles its tests. 302 selected Java tests and 18 offline
infrastructure contracts pass. PostgreSQL 18 migration/import SQL checks passed using PGlite;
Docker-backed runtime, TLS, Vault renewal, recovery and business end-to-end acceptance remain
pending. Recovered Wallet formatting fails the full formatting gate, and the unfinished Identity
audit adapter remains an application-startup blocker.

- Compose manages PostgreSQL 18, Vault, dependencies, networks, application Agents and
independent Agent/Flyway migration jobs. Existing persistent volumes have explicit external names.
- Vault Agent handles AppRole authentication, token/credential renewal and application restart
on credential replacement. Java consumes Agent token files for scoped KV access.
- Ansible replaces preparation, provisioning, initialization, migration orchestration, import,
identity refresh, backup and recovery launchers. The root `scripts/` directory and custom
Java migration/import/leased-datasource implementations are removed.
- The four existing versioned PostgreSQL SQL files are byte-for-byte unchanged; their hashes
are recorded in `infrastructure/migrations.sha256`. Wallet receives a separate V1 marker,
not a financial persistence implementation.
- Identity import and privilege checks retain `identity_challenge`, `identity_audit_log`, and
`identity_challenge_scope`. No SQL from the owner's unfinished Identity refactor is imported.
- Existing Identity KV scoping and pepper-rotation tests are retained. Their fixture helper now
requires Agent-delivered token paths in `PAYGUARD_REHEARSAL_OPERATOR_TOKEN_FILE`,
`PAYGUARD_REHEARSAL_IDENTITY_TOKEN_FILE`, and `PAYGUARD_REHEARSAL_WALLET_TOKEN_FILE`.
Those live Vault tests were not executed here.

## Executed checks

| Check | Result | Limit |
| --- | --- | --- |
| Offline deployment/security contracts | PASS, 18 tests | Configuration and HCL/TOML parsing, not live leases |
| Compose base/application/migration/operations configuration | PASS | Compose 2.40.3; no daemon |
| Compose production overlay configuration | PASS | Dummy external broker hosts and CA paths |
| Ansible playbook syntax | PASS, 21 entry points | `preflight.yml` is an imported task list, not a playbook |
| Fresh preparation | PASS | OpenSSL and Ansible on a new isolated fixture |
| Repeated fresh preparation | PASS, safely refused | Generated bytes unchanged; private keys/passwords/config 0600, directories 0700 |
| Existing versioned PostgreSQL SQL | PASS, 4 files unchanged | No live Flyway history available |
| Shared Agent token/TLS/error-sanitization Java tests | PASS, 5 tests | No live Vault; repository style goals skipped for this run |
| Application packaging and test-source compilation | PASS, all four services | Runtime tests skipped; Spotless/Checkstyle bypassed in this packaging run |
| Reactor Maven validation | PASS | Spotless and Checkstyle for parent/shared/four services; PMD/SpotBugs not run |
| Changed Java formatting | PASS | Google Java Format 1.30.0 |
| Original checkout WIP preservation | PASS | Original status, staging state and file hashes unchanged |

The Java test command used JDK 25 and the repository Maven wrapper:

```bash
./mvnw -B -ntp -pl payguard-shared \
-Dspotless.skip=true -Dcheckstyle.skip=true \
-Dtest=AgentTokenClientTest,PostgreSqlTlsTest,SanitizedDependencyErrorTest test
python3 -m unittest discover -s infrastructure/tests -v
```

Dependency downloads used private, workspace-only proxy settings and the system Java trust
store. TLS verification remained enabled; proxy settings and generated secrets are not committed.

## Required live acceptance

The reusable native infrastructure CI workflow runs on an isolated Docker host. It prepares
separate volumes, provisions Vault/databases, migrates every database twice, verifies privileges,
starts the applications and rehearses a Vault outage. The workflow is executable test scaffolding,
not evidence that those jobs have passed.

Production acceptance remains incomplete. Run integration, permission-denial, TLS failure,
Agent renewal/reauthentication, credential replacement, interrupted migration/recovery,
backup/restore, import rollback and business end-to-end tests before deployment. Test held SQL
transactions and Vault outages explicitly; credential expiration does not terminate every
already executing database statement. Complete paired PostgreSQL/Raft restoration and check
existing records, histories, ownership and secret versions on isolated recovery volumes.

Base Kafka is a local plaintext rehearsal broker. The production overlay requires authenticated
TLS external Redis/Kafka and verified CA/hostname settings. This is a single-host deployment
building block, not a tested highly available database or Vault deployment.
Historical infrastructure-only evidence from merged PR #40 is retained separately in
[infrastructure-before-recovery.md](recovery/infrastructure-before-recovery.md). It must not be
interpreted as validation of the recovered business refactor.
33 changes: 29 additions & 4 deletions docs/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ OTP key is missing, reconciliation fails rather than silently replacing that sta
historical SQL and Flyway checksums unchanged. An incompatible history needs a separate reviewed
forward migration; baseline/repair is deliberately not automatic.

The replacement import retains the committed `identity_challenge`, `identity_audit_log`, and
`identity_challenge_scope` tables. No old application data is
The replacement import retains the committed `identity_otp`, `identity_audit_log`, and
`identity_otp_scope` tables. No old application data is
converted or rewritten during adoption.

## Fresh isolated environment
Expand Down Expand Up @@ -166,7 +166,7 @@ Build the committed service modules with JDK 25, then migrate each database expl
This branch retains the existing module names and application persistence implementations:

```bash
./mvnw -B -ntp -pl payguard-identity-service,payguard-wallet-service,payguard-loan-service,payguard-collateral-service -am package
./mvnw -B -ntp -pl payguard-identity,payguard-wallet,payguard-loan,payguard-collateral -am package
for service in identity wallet loan collateral; do
docker compose run --rm --no-deps operations infrastructure/operations/migrate.yml -e service="$service"
done
Expand Down Expand Up @@ -225,13 +225,38 @@ single-host deployment building block, not an HA database/Vault design. Deployme
still requires live integration, security, recovery and business end-to-end checks. See the
current validation report for executed checks and remaining acceptance work.

## IDE database connections

To publish only the four database ports on localhost, run from the repository root:

```bash
docker compose -f docker-compose.yaml -f infrastructure/compose.ide.yaml up -d --no-deps postgres-wallet postgres-loan postgres-collateral postgres-identity
```

Use the PostgreSQL driver, host `127.0.0.1`, schema `payguard`, and these defaults:

| Service | Port | Database |
| --- | --- | --- |
| Wallet | 15431 | payguard_wallet |
| Loan | 15432 | payguard_loan |
| Collateral | 15433 | payguard_collateral |
| Identity | 15434 | payguard_identity |

For local administrative inspection, the username is `postgres` and each database's password is in `.local/payguard/<service>/admin-password`. This account has superuser privileges; do not use it in application configuration. Application credentials remain managed by Vault Agent.

Enable SSL with mode `verify-full` and CA certificate `.local/payguard/ca.crt` (use an absolute path in the IDE). No client certificate or key is required. Server certificates must include `IP:127.0.0.1` in their subject alternative names; older installations with only container DNS names need their server certificates reissued with the same CA before using this host. Fresh preparation already includes localhost names.

Override the ports with the `*_POSTGRES_PORT` settings from `.env.example`. The main Compose file alone keeps database ports private. The override reuses the existing external database volumes and does not initialize a replacement deployment.

If a local `.local/payguard/ide-image.yaml` exists, it records the exact previously installed PostgreSQL image for this workstation. Add `-f .local/payguard/ide-image.yaml` after the IDE override and use `--pull never` to reuse that image when the project-pinned image cannot be downloaded. This local file is ignored by Git and does not change the normal deployment image.

## Identity import

`import-identity.yml` replaces both the Python converter and Java import runner. Supply protected
`source_file`, `mapping_file`, and `approved_mapping_sha256` variables in a protected variable file.
The mapping JSON requires `approved_by`, `approval_reference`, `customers`, and `challenges`.
Already-correct prefixed IDs pass through; historical IDs require explicit mappings. The source
contains `challenges` and `audit` arrays. Audit records retain their `challenge_id` references.
contains `challenges` and `audit` arrays. Historical audit `challenge_id` fields map to `otp_id` in the recovered schema.

The native PostgreSQL transaction sets the stable owner, locks the destination, refuses populated
challenge/audit/scope tables, binds JSON values as parameters, checks integer/timestamp inputs,
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/application.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ FROM eclipse-temurin:25-jre-alpine@sha256:b7528962e65d43064d8a8b67ba175367896bc9
COPY --from=vault /bin/vault /usr/local/bin/vault
ARG SERVICE
WORKDIR /app
COPY payguard-${SERVICE}-service/target/payguard-${SERVICE}-service-1.0.0-SNAPSHOT.jar /app/service.jar
COPY payguard-${SERVICE}/target/payguard-${SERVICE}-1.0.0-SNAPSHOT.jar /app/service.jar
USER 1000:1000
ENTRYPOINT ["vault", "agent"]
20 changes: 20 additions & 0 deletions infrastructure/compose.ide.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Optional local IDE access; PostgreSQL remains private without this override.
services:
postgres-wallet:
networks: [database, ide]
ports:
- "127.0.0.1:${WALLET_POSTGRES_PORT:-15431}:5432"
postgres-loan:
networks: [database, ide]
ports:
- "127.0.0.1:${LOAN_POSTGRES_PORT:-15432}:5432"
postgres-collateral:
networks: [database, ide]
ports:
- "127.0.0.1:${COLLATERAL_POSTGRES_PORT:-15433}:5432"
postgres-identity:
networks: [database, ide]
ports:
- "127.0.0.1:${IDENTITY_POSTGRES_PORT:-15434}:5432"
networks:
ide: {}
Loading
Loading