Skip to content

Commit bba747e

Browse files
committed
Merge main and address CI runtime review feedback
2 parents df6e646 + dee841f commit bba747e

24 files changed

Lines changed: 821 additions & 185 deletions

.github/workflows/CDA-testing.yml

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,39 @@ on:
99

1010
jobs:
1111
integration-tests:
12+
name: integration-tests (Python ${{ matrix.python-version }}, CDA ${{ matrix.cda.name }},
13+
schema ${{ matrix.schema.name }})
1214
runs-on: ubuntu-latest
15+
timeout-minutes: 60
16+
17+
strategy:
18+
fail-fast: false
19+
max-parallel: 6
20+
matrix:
21+
python-version: ['3.9', '3.13']
22+
# Keep the release pins in sync with the environments (see CONTRIBUTING.md).
23+
cda:
24+
- name: latest
25+
image: ghcr.io/usace/cwms-data-api:develop-nightly
26+
- name: production
27+
image: ghcr.io/usace/cwms-data-api:2026.05.12-i
28+
- name: test
29+
image: ghcr.io/usace/cwms-data-api:2026.08.31-testd
30+
schema:
31+
- name: latest
32+
tag: latest-dev
33+
- name: production
34+
tag: '26.02.17'
35+
- name: test
36+
tag: 26.07.16-RC02
37+
38+
env:
39+
CWMS_DATA_API_IMAGE: ${{ matrix.cda.image }}
40+
CWMS_DATABASE_IMAGE: ghcr.io/hydrologicengineeringcenter/cwms-database/cwms/database-ready-ora-23.5:${{ matrix.schema.tag }}
41+
CWMS_SCHEMA_INSTALLER_IMAGE: ghcr.io/hydrologicengineeringcenter/cwms-database/cwms/schema_installer:${{ matrix.schema.tag }}
1342

1443
steps:
15-
- uses: actions/checkout@v6
44+
- uses: actions/checkout@v7
1645

1746
- name: Clean up disk space, so we don't run out.
1847
if: runner.os == 'Linux'
@@ -24,12 +53,13 @@ jobs:
2453
- name: Set up backend
2554
run: |
2655
docker compose pull
27-
docker compose up -d
56+
docker compose up -d --wait --wait-timeout 2400
2857
2958
- name: Set Up Python
59+
id: setup-python
3060
uses: actions/setup-python@v6
3161
with:
32-
python-version: '3.9.X'
62+
python-version: ${{ matrix.python-version }}
3363

3464
# Use actions-poetry to handle installation
3565
- name: Install Poetry and Dependencies
@@ -41,11 +71,12 @@ jobs:
4171

4272
# Poetry will handle installation and caching
4373
- name: Cache Python dependencies
44-
uses: actions/cache@v5
74+
uses: actions/cache@v6
4575
id: cache-poetry-venv
4676
with:
4777
path: .venv
48-
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
78+
key: ${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-poetry-${{
79+
hashFiles('poetry.lock') }}
4980

5081
# Install dependencies only if cache is missed
5182
- name: Install dependencies
@@ -72,3 +103,11 @@ jobs:
72103
file: ./code-coverage-results.md
73104
vars: |-
74105
empty: empty
106+
107+
- name: Show backend logs on failure
108+
if: failure()
109+
run: docker compose logs --no-color --tail 200
110+
111+
- name: Stop test backend
112+
if: always()
113+
run: docker compose down --volumes

.github/workflows/code-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010

1111
steps:
12-
- uses: actions/checkout@v6
12+
- uses: actions/checkout@v7
1313

1414
# Verify that python files are formatted using black and isort. Both of the actions
1515
# below simply check the source code and fail if they find any files that need to be

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout repository
17-
uses: actions/checkout@v6
17+
uses: actions/checkout@v7
1818

1919
- name: Initialize CodeQL
2020
uses: github/codeql-action/init@v4

.github/workflows/pypi-deploy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
steps:
15-
- uses: actions/checkout@v6
15+
- uses: actions/checkout@v7
1616

1717
- name: Set Up Python
1818
uses: actions/setup-python@v6
@@ -23,7 +23,7 @@ jobs:
2323
uses: abatilo/actions-poetry@v4
2424

2525
- name: Cache Virtual Environment
26-
uses: actions/cache@v5
26+
uses: actions/cache@v6
2727
with:
2828
path: ./.venv
2929
key: venv-${{ hashFiles('poetry.lock') }}
@@ -92,7 +92,7 @@ jobs:
9292
path: dist/
9393

9494
- name: Sign Distribution
95-
uses: sigstore/gh-action-sigstore-python@v3.3.0
95+
uses: sigstore/gh-action-sigstore-python@v3.4.0
9696
with:
9797
inputs: |
9898
./dist/*.tar.gz

.github/workflows/test-deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020

2121
steps:
22-
- uses: actions/checkout@v6
22+
- uses: actions/checkout@v7
2323

2424
- name: Set Up Python
2525
uses: actions/setup-python@v6
@@ -30,7 +30,7 @@ jobs:
3030
uses: abatilo/actions-poetry@v4
3131

3232
- name: Cache Virtual Environment
33-
uses: actions/cache@v5
33+
uses: actions/cache@v6
3434
with:
3535
path: ./.venv
3636
key: venv-${{ hashFiles('poetry.lock') }}

.github/workflows/testing.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,25 @@ jobs:
99
runs-on: ubuntu-latest
1010

1111
steps:
12-
- uses: actions/checkout@v6
12+
- uses: actions/checkout@v7
1313

1414
- name: Set Up Python
15+
id: setup-python
1516
uses: actions/setup-python@v6
1617
with:
17-
python-version: '3.12'
18+
python-version: '3.13'
1819

1920
# Unlike the code-check workflow, this job requires the dev dependencies to be
2021
# installed to make sure we have the necessary, tools, stub files, etc.
2122
- name: Install Poetry
2223
uses: abatilo/actions-poetry@v4
2324

2425
- name: Cache Virtual Environment
25-
uses: actions/cache@v5
26+
uses: actions/cache@v6
2627
with:
2728
path: ./.venv
28-
key: ${{ runner.os }}-py3.12-venv-${{ hashFiles('poetry.lock') }}
29+
key: ${{ runner.os }}-py${{ steps.setup-python.outputs.python-version }}-venv-${{
30+
hashFiles('poetry.lock') }}
2931

3032
- name: Install Dependencies
3133
run: poetry install

CONTRIBUTING.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,46 @@ passed, bearer token auth takes precedence.
7979
8080
> **Note:** If you are running other instances of CDA or Oracle on your machine, they may use different ports. Always verify which ports are in use and update your configuration files accordingly to avoid conflicts.
8181
82+
#### Selecting CDA and Database Versions
83+
84+
Local Compose defaults to CDA `develop-nightly` and database/schema-installer
85+
`latest-dev`. Override the image references in a local, uncommitted `.env`
86+
file when reproducing a particular environment, for example:
87+
88+
```dotenv
89+
CWMS_DATA_API_IMAGE=ghcr.io/usace/cwms-data-api:2026.05.12-i
90+
CWMS_DATABASE_IMAGE=ghcr.io/hydrologicengineeringcenter/cwms-database/cwms/database-ready-ora-23.5:26.02.17
91+
CWMS_SCHEMA_INSTALLER_IMAGE=ghcr.io/hydrologicengineeringcenter/cwms-database/cwms/schema_installer:26.02.17
92+
```
93+
94+
Keep the database and schema-installer tags together. Use a separate Compose
95+
project for each database version, so the test data and containers are isolated:
96+
97+
```sh
98+
docker compose -p cwms-python-release pull
99+
docker compose -p cwms-python-release up -d --wait --wait-timeout 2400
100+
```
101+
102+
Use the same project name for subsequent `ps`, `logs`, and `down` commands.
103+
Stop the previous stack before starting another one using the same host ports.
104+
105+
The integration workflow in `.github/workflows/CDA-testing.yml` tests every
106+
combination of three CDA images and three database versions on Python 3.9
107+
and 3.13 (18 jobs):
108+
109+
| Lane | CDA tag | Database and schema-installer tag |
110+
| --- | --- | --- |
111+
| latest | `develop-nightly` | `latest-dev` |
112+
| production | `2026.05.12-i` | `26.02.17` |
113+
| test | `2026.08.31-testd` | `26.07.16-RC02` |
114+
115+
These release pins are maintained in the workflow; update them when the
116+
target environments change. CDA and database are independent matrix axes,
117+
so testing includes mixed versions, not only the three same-lane pairs.
118+
Each job starts a disposable local stack, waits for backend health, and
119+
uses the hashed test keys seeded by `compose_files/sql/users.sql`. CI never
120+
runs these destructive integration tests against the deployed environments.
121+
82122
3. **Run Tests Against CDA**
83123
Once the services are running, execute the tests:
84124
```sh

compose_files/sql/users.sql

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,56 @@
11
set define on
22
define OFFICE_EROC=&1
3+
declare
4+
type office_list_t is table of varchar2(16);
5+
6+
procedure add_full_admin(p_user varchar2, p_offices office_list_t) is
7+
begin
8+
for i in 1 .. p_offices.count loop
9+
cwms_sec.add_cwms_user(p_user, NULL, p_offices(i));
10+
cwms_sec.add_user_to_group(p_user, 'All Users', p_offices(i));
11+
cwms_sec.add_user_to_group(p_user, 'CWMS Users', p_offices(i));
12+
cwms_sec.add_user_to_group(p_user, 'TS ID Creator', p_offices(i));
13+
cwms_sec.add_user_to_group(p_user, 'CWMS User Admins', p_offices(i));
14+
cwms_sec.add_user_to_group(p_user, 'CWMS PD Users', p_offices(i));
15+
end loop;
16+
end;
317
begin
418
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','All Users', 'HQ');
519
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','All Users', 'SPK');
20+
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','All Users', 'MVP');
21+
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','All Users', 'LRL');
622
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','CWMS Users', 'HQ');
723
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','CWMS User Admins', 'HQ');
8-
24+
cwms_sec.add_user_to_group('&&OFFICE_EROC.webtest','CWMS PD Users', 'HQ');
925

10-
cwms_sec.add_cwms_user('l2hectest',NULL,'SPK');
11-
cwms_sec.update_edipi('l2hectest',1234567890);
12-
cwms_sec.add_user_to_group('l2hectest','All Users', 'SPK');
13-
cwms_sec.add_user_to_group('l2hectest','CWMS Users', 'SPK');
14-
cwms_sec.add_user_to_group('l2hectest','TS ID Creator','SPK');
15-
cwms_sec.add_user_to_group('l2hectest','CWMS User Admins', 'SPK');
26+
add_full_admin('l2hectest', office_list_t('SPK'));
27+
cwms_sec.update_edipi('l2hectest', 1234567890);
1628

17-
cwms_sec.add_cwms_user('l1hectest',NULL,'SPL');
29+
cwms_sec.add_cwms_user('l1hectest', NULL, 'SPL');
1830
-- intentionally no extra permissions.
19-
--cwms_sec.add_user_to_group('l2hectest','CWMS Users', 'SPL');
2031

21-
cwms_sec.add_cwms_user('m5hectest',NULL,'SWT');
32+
cwms_sec.add_cwms_user('m5hectest', NULL, 'SWT');
2233
cwms_sec.add_user_to_group('m5hectest','All Users', 'SWT');
2334
cwms_sec.add_user_to_group('m5hectest','CWMS Users', 'SWT');
2435
execute immediate 'grant execute on cwms_20.cwms_upass to web_user';
2536

26-
2737
cwms_sec.add_cwms_user('m5testadmin', NULL, 'LRL');
2838
cwms_sec.add_user_to_group('m5testadmin','All Users', 'LRL');
2939
cwms_sec.add_user_to_group('m5testadmin','CWMS Users', 'LRL');
3040
cwms_sec.add_user_to_group('m5testadmin','CWMS User Admins', 'LRL');
41+
cwms_sec.add_user_to_group('m5testadmin','CWMS PD Users', 'LRL');
42+
43+
add_full_admin('q0hectest', office_list_t('LRL', 'SPK', 'MVP'));
3144

32-
cwms_sec.add_cwms_user('q0hectest', NULL, 'LRL');
33-
cwms_sec.add_user_to_group('q0hectest','All Users', 'LRL');
34-
cwms_sec.add_user_to_group('q0hectest','CWMS Users', 'LRL');
35-
cwms_sec.add_user_to_group('q0hectest','TS ID Creator','LRL');
36-
cwms_sec.add_user_to_group('q0hectest','CWMS User Admins', 'LRL');
37-
38-
cwms_sec.add_cwms_user('q0hectest', NULL, 'SPK');
39-
cwms_sec.add_user_to_group('q0hectest','All Users', 'SPK');
40-
cwms_sec.add_user_to_group('q0hectest','CWMS Users', 'SPK');
41-
cwms_sec.add_user_to_group('q0hectest','TS ID Creator','SPK');
42-
cwms_sec.add_user_to_group('q0hectest','CWMS User Admins', 'SPK');
43-
44-
cwms_sec.add_cwms_user('q0hectest', NULL, 'MVP');
45-
cwms_sec.add_user_to_group('q0hectest','All Users', 'MVP');
46-
cwms_sec.add_user_to_group('q0hectest','CWMS Users', 'MVP');
47-
cwms_sec.add_user_to_group('q0hectest','TS ID Creator','MVP');
48-
cwms_sec.add_user_to_group('q0hectest','CWMS User Admins', 'MVP');
49-
50-
insert into cwms_20.at_api_keys (userid, key_name, apikey) values ('Q0HECTEST', 'testkey', '0123456789abcdef0123456789abcdef');
51-
insert into cwms_20.at_api_keys (userid, key_name, apikey) values ('L2HECTEST', 'testkey2', '1234567890abcdef1234567890abcdef');
45+
insert into cwms_20.at_api_keys (userid, key_name, apikey, created, expires) values ('Q0HECTEST', 'testkey', 'ak1_CYflBX6c$argon2id$v=19$m=19456,t=2,p=1$8Wh8X9m+O81UvrbCJ/eOFQ$+E0Rp3jhjduIHxaqmzx+OLR43B3HdcMuDyn8cO5/69s', sysdate, sysdate + 365);
46+
-- key is ak1_CYflBX6cQOHlJkkcsA6NPvJ7npm1kynzfUsa45ncIPcGNewkcvK2ounQN8MaDj8Wkc8o0HiZvLkETpGrGkl3OvJD9Nt0vQCIPLBeqQiLGBQHsPDZmk1gEkVCzubSyfKy31bagcf0jrajn6zCcRAv1tpMpnucFCkUwCpTYwNCfCnPkqukNVpOyTv7I2II8NIxBQmQOZPc09yOrKPkQpj1sHM4NNxIcUfTZrPpidT1QGjhfVaaWW1AiqodkxXPxlTqvuRLz9bL
47+
48+
insert into cwms_20.at_api_keys (userid, key_name, apikey, created, expires) values ('L2HECTEST', 'testkey2', 'ak1_3rF3RXlB$argon2id$v=19$m=19456,t=2,p=1$xxL2ItUkn3gC1LT5F8Wb0g$2az8A0GpJVVhbaccD4ICVWvnM2uoKzU652r9jemE9qg', sysdate, sysdate + 365);
49+
-- key is ak1_3rF3RXlBRpWiWNdBhrX5LwNnbwyPX7J9MDro8b3aoRVp2bM4FRZPsOZOoFtjVuwt9bNnniWqzIaCfTzKNUqdp43ItSk7oFLdqf05gVhM5UtaLZa2BN7KNdb7hSxYu6FQJkt8haSQK3swUaC9qlRFLIPMerbjxxIF8UnuQ7Oe54uyiN7JJaaHErI0m7qo7ir2bkxHvC0aWw9UkT9Z8RKfWeaQBIizqZnicqmXgsekLvqwkZ2jJrLUw180aFr5g7rCEsRtVtRE
5250
-- Non-admin API key for the L1 with reduced permissions
5351
-- Used by CDA user-management tests that verify 403 handling
54-
insert into cwms_20.at_api_keys (userid, key_name, apikey) values ('L1HECTEST', 'non_admin_test_key', 'fedcba9876543210fedcba9876543210');
55-
52+
insert into cwms_20.at_api_keys (userid, key_name, apikey, created, expires) values ('L1HECTEST', 'non_admin_test_key', 'ak1_SZUNxN3n$argon2id$v=19$m=19456,t=2,p=1$KAlZGdgEboEHvEVcpNGD0g$pPCCkQfOx8v5HNpwPadJNUHGI0I40a7HgcZ7JsTE6T0', sysdate, sysdate + 365);
53+
-- key is ak1_SZUNxN3nDx0NpUfOJxpOuGqbqRKdYjbx86x6YVISLb9DiBi3Io5o6T6UFvkHknjIRnRO6oQfA1q6rP4XRDYMH9Hlr4ndffL6NjxPUaBZLSnqukV0uGuZKOUWBB04L5SyloJniOHkFe6ymvB9tzeziGYwzrDv3k6lzacG9vftHkCHB1QbjwwCC0sDkFvuwCe9qnyx5us11qL0YAfKXhe0fBCA2TmNDz8WXfw1HfBnAKx6WD7KqHngplWu4miOvkNverxFmAdJ
5654
end;
5755
/
5856
quit;

compose_files/togglz/features.properties

Lines changed: 0 additions & 3 deletions
This file was deleted.

cwms/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from cwms.levels.specified_levels import *
1111
from cwms.locations.gate_changes import *
1212
from cwms.locations.location_groups import *
13+
from cwms.locations.lookups import *
1314
from cwms.locations.physical_locations import *
1415
from cwms.measurements.measurements import *
1516
from cwms.outlets.outlets import *
@@ -18,6 +19,7 @@
1819
from cwms.projects.project_locks import *
1920
from cwms.projects.projects import *
2021
from cwms.projects.water_supply.accounting import *
22+
from cwms.properties.properties import *
2123
from cwms.ratings.ratings import *
2224
from cwms.ratings.ratings_spec import *
2325
from cwms.ratings.ratings_template import *

0 commit comments

Comments
 (0)