2. Set up a development environment

This tutorial takes you from a clean machine to a local C-PAT instance you can sign in to, with the API and client running from source and both test suites passing. It works on Windows and Linux. Expect it to take about an hour the first time, most of it waiting on downloads.

2.1. Prerequisites

Install the following before you begin:

  • Node.js 22.12 or later. The API declares "node": ">=22.12.0" in api/package.json, and both packages set engine-strict = true in their .npmrc, so an older Node refuses to install dependencies. CI runs on Node 22.

  • Git.

  • Docker. You use it for the identity provider, the database, and the documentation build. Docker Desktop on Windows works with the commands below.

  • MySQL 8.0.24 or later, in a container or installed locally. The API checks the server version at startup (minMySqlVersion in api/Services/utils.js) and refuses anything older. The MySQL event scheduler must be on; it is on by default in MySQL 8.0, and a migration creates a scheduled event that updates POAM statuses.

  • The demonstration identity provider, nswccrane/c-pat-auth on Docker Hub. It is a Keycloak image with the RMFTools realm, the c-pat and stig-manager clients, and the roles C-PAT expects.

STIG Manager and Tenable.sc are optional. Without them the client hides the integration pages through the features block of its runtime configuration. The stig-manager OIDC client must still exist in the realm, because the web client authenticates against both clients before it shows any page; the demonstration realm includes it.

2.2. Start the supporting services

Start Keycloak and MySQL as containers. The API’s defaults expect Keycloak on port 8080 and MySQL on port 3306 of localhost.

docker run -d --name c-pat-auth -p 8080:8080 nswccrane/c-pat-auth
docker run -d --name c-pat-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=change-me mysql:8.0

The c-pat-auth README on Docker Hub lists the maintained run script and the test accounts the realm ships with (admin and user01 through user05). The Keycloak admin console is at http://localhost:8080.

Create the database and the account the API will use. Connect to MySQL as root and run:

CREATE DATABASE cpat;
CREATE USER 'cpat'@'%' IDENTIFIED BY 'change-me';
GRANT ALL ON cpat.* TO 'cpat';

You should see three Query OK responses. The API creates every table itself on first start. The Database page explains the account requirements and suggested server settings.

2.3. Configure the API

The API reads its configuration from environment variables, and in development from a .env file in the api/ directory. dotenv loads the file from the working directory, so always start the API from api/.

  1. Clone the repository and copy the template:

    git clone https://github.com/NSWC-Crane/C-PAT.git
    cd C-PAT\api
    Copy-Item example_env.txt .env
    
  2. Open .env and set the database values to match the container you started: CPAT_DB_HOST=localhost, CPAT_DB_PORT=3306, CPAT_DB_SCHEMA=cpat, CPAT_DB_USER=cpat, and CPAT_DB_PASSWORD.

  3. Set CPAT_OIDC_PROVIDER=http://localhost:8080/realms/RMFTools.

  4. Set CPAT_SWAGGER_ENABLED=true so the API serves Swagger UI at /api-docs.

  5. Optionally set CPAT_LOG_LEVEL=4 to log request and response bodies, and CPAT_DEV_RESPONSE_VALIDATION=logOnly to have the OpenAPI validator log responses that do not match the contract. Both are development conveniences; leave them unset in any deployed environment.

The full variable reference is in Environment Variables.

Warning

The API refuses to start when the identity provider publishes a signing key that the API recognizes as a shared demonstration key. If the startup log reports an insecure signing key, you are using the demonstration realm. Set CPAT_DEV_ALLOW_INSECURE_TOKENS=true in .env on your development machine only. Never set it anywhere a real user can sign in.

2.4. Run the API

Install the dependencies from the lockfile and start the server:

npm ci
npm start

The API logs one JSON object per line. On the first start you should see, in this order:

  1. A bootstrapUtils record with the version and the effective configuration (the database password is masked).

  2. A server record of type listening reporting port 8086 and the paths /api, /docs, and /api-docs. The port is open at this point, but requests are not served yet.

  3. oidc records as the API fetches the provider’s discovery document and signing keys.

  4. mysql records: the empty schema is populated from api/Services/migrations/sql/current/, then every migration in api/Services/migrations/ runs and logs migration records with status values start, running, and finish.

  5. A server record of type started with the startup duration.

Until both the database and the identity provider are ready, every request receives 503 Service Unavailable with a JSON body describing the API state. That is the availability gate, not a failure; wait for the started record. Requests to /docs return 404 until you build the documentation in a later step.

2.5. Run the client

The client runs from source with the Angular dev server on port 4200 and calls the API on port 8086.

  1. Install the dependencies. The --force flag is required; the reason is on the Dependencies and upgrades page.

    cd ../client
    npm install --force
    
  2. Create the development index page from its template. The dev server uses src/development.html as its index, and that file is git-ignored so that every developer can hold local values in it.

    Copy-Item src\development.example.html src\development.html
    
  3. Open src/development.html and edit the CPAT.Env object near the top. In production the API injects this object; in development you maintain it by hand. Confirm apiBase is http://localhost:8086/api, client.authority and oauth.authority are http://localhost:8080/realms/RMFTools, oauth.clientId is c-pat, and stigman.clientId is stig-manager. Set stigman.apiUrl to your STIG Manager API if you run one. Set primeng.license to your own PrimeNG license key, or leave it empty and accept the license notice in the client.

  4. Start the dev server and open http://localhost:4200:

    npm start
    

You should see the compilation finish with bundle generation complete and the browser redirect to the Keycloak sign-in page.

Warning

src/development.html is ignored by git on purpose. Never commit it, and never copy a license key from it into a tracked file.

2.6. Sign in and activate your user

Sign in with one of the realm’s test accounts. The client authenticates against the stig-manager client first and then the c-pat client, so you may see two redirects. On the first sign-in the API creates your user record with the account status PENDING, and the client shows the not-activated page.

An administrator activates accounts in the Admin Portal, under User Management, by setting the account status to ACTIVE. Administrators are users whose token carries the admin realm role; in the demonstration realm, sign in as admin to do this. See Administration Portal.

If no account in your realm carries the admin role, activate your first user directly in the database:

UPDATE cpat.user SET accountStatus = 'ACTIVE' WHERE userName = 'admin';

Reload the client. You should see the home page. Users also need a permission on at least one collection before they can see data; an administrator grants those in the Admin Portal as well.

2.7. Verify the setup

  1. Open http://localhost:8086/api-docs. Click Authorize, sign in, and call GET /user. You should get your own user record as JSON. Swagger UI uses the same PKCE flow as the client.

  2. Run the API tests from api/:

    npm test
    

    The Node.js test runner prints one line per test and ends with # pass and # fail 0 counts.

  3. Lint the API contract from api/:

    npm run lint:spec
    

    Redocly prints Woohoo! Your API description is valid when the contract passes.

  4. Run the client tests from client/:

    npm run test:run
    

    Vitest ends with a summary of test files and tests passed.

2.8. Run the production shape locally

In production the API serves the built client and the built documentation itself. To see that shape:

  1. Build the client and start the API in one command from api/:

    npm run offline-rebuild
    

    The API serves the bundle from ../client/dist/browser (the CPAT_CLIENT_DIRECTORY default). Open http://localhost:8086.

  2. Build the documentation so /docs works. The build runs in a container; on Windows, run it from PowerShell, because Git Bash rewrites the volume path and the build fails with config directory doesn't contain a conf.py file.

    cd ..\docs
    docker build -t sphinx-w-requirements .
    docker run --rm -v "${PWD}:/docs" sphinx-w-requirements make html
    

    Open http://localhost:8086/docs. See Documentation for the build in detail.

Note

Two Windows details save time. Git Bash converts POSIX-style paths in Docker volume arguments; use PowerShell or set MSYS_NO_PATHCONV=1. And core.autocrlf is usually true on Windows checkouts; if a formatter run produces changes in every file, you ran one package’s formatter over the other package’s files. See Coding standards.

2.9. Next steps