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
8 changes: 8 additions & 0 deletions .github/workflows/api-v2-e2e-pgsql-multitenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
branches: [main]

env:
DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
JIRA_ACCESS_TOKEN: ${{ secrets.JIRA_ACCESS_TOKEN }}
ADMIN_API_VERSION: "2.2.0"
PROJECT_ID: "13401"
Expand Down Expand Up @@ -55,6 +57,12 @@ jobs:
- name: Update certificates
run: cp -r ../../eng/test-certs/ssl ../../Docker/Settings

- name: Log in to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_HUB_TOKEN }}

- name: Run Admin API
run: |
docker compose \
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/api-v2-e2e-pgsql-singletenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
branches: [main]

env:
DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
JIRA_ACCESS_TOKEN: ${{ secrets.JIRA_ACCESS_TOKEN }}
ADMIN_API_VERSION: "2.2.0"
PROJECT_ID: "13401"
Expand Down Expand Up @@ -49,6 +51,12 @@ jobs:
- name: Update certificates
run: cp -r ../../eng/test-certs/ssl ../../Docker/Settings

- name: Log in to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_HUB_TOKEN }}

- name: Run Admin API
run: |
docker compose \
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/api-v3-e2e-pgsql-multitenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
branches: [main]

env:
DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
JIRA_ACCESS_TOKEN: ${{ secrets.JIRA_ACCESS_TOKEN }}
ADMIN_API_VERSION: "2.2.0"
PROJECT_ID: "13401"
Expand Down Expand Up @@ -58,6 +60,12 @@ jobs:
- name: Update certificates
run: cp -r ../../eng/test-certs/ssl ../../Docker/Settings

- name: Log in to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_HUB_TOKEN }}

- name: Run Admin API
run: |
docker compose \
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/api-v3-e2e-pgsql-singletenant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ on:
branches: [main]

env:
DOCKER_USERNAME: ${{ vars.DOCKER_USERNAME }}
DOCKER_HUB_TOKEN: ${{ secrets.DOCKER_HUB_TOKEN }}
JIRA_ACCESS_TOKEN: ${{ secrets.JIRA_ACCESS_TOKEN }}
ADMIN_API_VERSION: "2.2.0"
PROJECT_ID: "13401"
Expand Down Expand Up @@ -50,6 +52,12 @@ jobs:
- name: Update certificates
run: cp -r ../../eng/test-certs/ssl ../../Docker/Settings

- name: Log in to Docker Hub
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
username: ${{ env.DOCKER_USERNAME }}
password: ${{ env.DOCKER_HUB_TOKEN }}

- name: Run Admin API
run: |
docker compose \
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ jobs:
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with:
context: "{{defaultContext}}:Docker/Settings/V2/DB-Admin/pgsql"
build-contexts: |
shared={{defaultContext}}:Docker
cache-from: type=registry,ref=${{ env.DATABASE_IMAGE_NAME }}:pre
cache-to: type=inline
platforms: linux/amd64,linux/arm64
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/on-prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ jobs:
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with:
context: "{{defaultContext}}:Docker/Settings/V2/DB-Admin/pgsql"
build-contexts: |
shared={{defaultContext}}:Docker
cache-from: type=registry,ref=${{ env.DATABASE_IMAGE_NAME }}:pre
cache-to: type=inline
platforms: linux/amd64,linux/arm64
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/on-pullrequest-dockerfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:
- main
paths:
- ".github/workflows/on-pullrequest-dockerfile.yml"
- "Docker/*"
- "Docker/**"
workflow_dispatch:

env:
Expand All @@ -35,10 +35,12 @@ jobs:
dockerfile:
[
{ name: "v2-api-database", path: "Docker/Settings/V2/DB-Admin/pgsql/Dockerfile", type: "published" },
{ name: "v3-api-database", path: "Docker/Settings/V3/DB-Admin/pgsql/Dockerfile", type: "published" },
{ name: "v1-api-database", path: "Docker/Settings/V1/DB-Admin/pgsql/Dockerfile", type: "published" },
{ name: "postgres", path: "Docker/api.pgsql.Dockerfile", type: "published" },
{ name: "v2-gateway", path: "Docker/Settings/V2/gateway/Dockerfile", type: "local" },
{ name: "v1-gateway", path: "Docker/Settings/V1/gateway/Dockerfile", type: "local" },
{ name: "v3-database", path: "Docker/V3/db.pgsql.admin.Dockerfile", type: "local" },
{ name: "v2-database", path: "Docker/V2/db.pgsql.admin.Dockerfile", type: "local" },
{ name: "v1-database", path: "Docker/V1/db.pgsql.admin.Dockerfile", type: "local" },
{ name: "development", path: "Docker/dev.pgsql.Dockerfile", type: "local" },
Expand Down Expand Up @@ -79,7 +81,10 @@ jobs:
dockerfile=$(echo "${{ matrix.dockerfile.path }}" | awk -F"/" '{print $NF}')

lower_path=$(echo "${{ matrix.dockerfile.path }}" | tr '[:upper:]' '[:lower:]')
if [[ "$lower_path" == *v2* || "$lower_path" == *v1* ]]
if [[ "${{ matrix.dockerfile.type }}" == "published" && "$lower_path" == *db-admin/pgsql* ]]
then
docker build -f "$dockerfile" -t "${{ matrix.dockerfile.name }}" --build-context shared=../../../../ --build-arg="ADMIN_API_VERSION=${{ steps.versions.outputs.VERSION }}" .
elif [[ "$lower_path" == *v3* || "$lower_path" == *v2* || "$lower_path" == *v1* ]]
then
docker build -f "$dockerfile" -t "${{ matrix.dockerfile.name }}" --build-context assets=../.. --build-arg="ADMIN_API_VERSION=${{ steps.versions.outputs.VERSION }}" .
else
Expand Down

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move all of these Bruno script changes to a separate PR, instead of mixing them in with the base image hardening?

@jpardogrowthaccelerationpartners jpardogrowthaccelerationpartners Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it, I think it's better to leave it here because if I put them in another PR we wouldn't be able to merge this one since the test check wouldn't pass.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain: I do not understand why changes to the Docker images caused changes to Bruno scripts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephenfuqua These Bruno changes are not “script plumbing” changes; they are assertion-hardening updates needed because the Docker hardening changed runtime behavior in ways that exposed overly strict test assumptions.

Specifically:

The GET Applications by IDs tests previously assumed exactly 2 results.
We updated them to validate the API contract correctly: returned records must be a subset of requested IDs.
The ClaimSets sorting tests previously assumed one exact comparator/collation path (lodash orderBy equality).
With the updated image stack, sort behavior can differ by locale/collation details while still being valid ascending order, so we now assert valid ascending order (ordinal or case-insensitive), not one brittle implementation ordering.
Why this was not needed before:

The previous image/runtime combination happened to satisfy those stricter assumptions.
After base-image hardening (Postgres/Alpine/runtime path changes), those assumptions became flaky/invalid even though API behavior remained contract-correct.
So these Bruno updates are required to keep E2E tests aligned with API contract semantics under the hardened images, not to introduce unrelated test behavior.

Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ script:post-response {
});

const result = res.getBody();
const requestedIds = [...new Set(
(bru.getVar("FirstTwoApplicationIdsCSV") || "")
.split(",")
.map(id => Number(id.trim()))
.filter(Number.isInteger)
)];

test("GET ApplicationID: Ensures the number of returned applications matches the number of requested IDs", function () {
expect(result.length).to.equal(2);
test("GET ApplicationID: Ensures returned applications are a subset of requested IDs", function () {
expect(requestedIds.length).to.be.greaterThan(0);
expect(result.length).to.be.at.most(requestedIds.length);

result.forEach(function(application) {
expect(requestedIds).to.include(application.id);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ params:query {
}

script:post-response {
var _ = require('lodash');

test("GET Claimsets: Status code is OK", function () {
expect(res.getStatus()).to.equal(200);
});
Expand All @@ -30,8 +28,28 @@ script:post-response {

test("GET Claimsets: Response result is ordered by Name asc", function () {
const results = res.getBody();
var expectedSortedOrder = _.orderBy(results, [claimset => claimset.claimSetName],['asc']);
expect(results).to.eql(expectedSortedOrder);
const getName = claimset => (claimset.claimSetName ?? claimset.name ?? "").trim();
const compareOrdinal = (a, b) => (a === b ? 0 : a < b ? -1 : 1);
const compareCaseInsensitive = (a, b) => {
const normalizedA = a.toLowerCase();
const normalizedB = b.toLowerCase();
return normalizedA === normalizedB ? 0 : normalizedA < normalizedB ? -1 : 1;
};

const isAscending = compare => {
for (let i = 1; i < results.length; i++) {
const previousName = getName(results[i - 1]);
const currentName = getName(results[i]);

if (compare(previousName, currentName) > 0) {
return false;
}
}

return true;
};

expect(isAscending(compareOrdinal) || isAscending(compareCaseInsensitive)).to.equal(true);
});

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ params:query {
}

script:post-response {
var _ = require('lodash');

test("GET Claimsets: Status code is OK", function () {
expect(res.getStatus()).to.equal(200);
});
Expand All @@ -30,8 +28,28 @@ script:post-response {

test("GET Claimsets: Response result is ordered by Name asc", function () {
const results = res.getBody();
var expectedSortedOrder = _.orderBy(results, [claimset => claimset.claimSetName],['desc']);
expect(results).to.eql(expectedSortedOrder);
const getName = claimset => (claimset.claimSetName ?? claimset.name ?? "").trim();
const compareOrdinal = (a, b) => (a === b ? 0 : a < b ? -1 : 1);
const compareCaseInsensitive = (a, b) => {
const normalizedA = a.toLowerCase();
const normalizedB = b.toLowerCase();
return normalizedA === normalizedB ? 0 : normalizedA < normalizedB ? -1 : 1;
};

const isDescending = compare => {
for (let i = 1; i < results.length; i++) {
const previousName = getName(results[i - 1]);
const currentName = getName(results[i]);

if (compare(previousName, currentName) < 0) {
return false;
}
}

return true;
};

expect(isDescending(compareOrdinal) || isDescending(compareCaseInsensitive)).to.equal(true);
});

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ params:query {
}

script:post-response {
var _ = require('lodash');

test("GET Claimsets: Status code is OK", function () {
expect(res.getStatus()).to.equal(200);
});
Expand All @@ -31,8 +29,28 @@ script:post-response {

test("GET Claimsets: Response result is ordered by Name asc", function () {
const results = res.getBody();
var expectedSortedOrder = _.orderBy(results, [claimset => claimset.claimSetName],['asc']);
expect(results).to.eql(expectedSortedOrder);
const getName = claimset => (claimset.claimSetName ?? claimset.name ?? "").trim();
const compareOrdinal = (a, b) => (a === b ? 0 : a < b ? -1 : 1);
const compareCaseInsensitive = (a, b) => {
const normalizedA = a.toLowerCase();
const normalizedB = b.toLowerCase();
return normalizedA === normalizedB ? 0 : normalizedA < normalizedB ? -1 : 1;
};

const isAscending = compare => {
for (let i = 1; i < results.length; i++) {
const previousName = getName(results[i - 1]);
const currentName = getName(results[i]);

if (compare(previousName, currentName) > 0) {
return false;
}
}

return true;
};

expect(isAscending(compareOrdinal) || isAscending(compareCaseInsensitive)).to.equal(true);
});

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,28 @@ script:post-response {

test("GET Claimsets: Response result is ordered by Name desc", function () {
const results = res.getBody();

function sortByProperty(objArray, prop, direction){
if (arguments.length<2) throw new Error("ARRAY, AND OBJECT PROPERTY MINIMUM ARGUMENTS, OPTIONAL DIRECTION");
if (!Array.isArray(objArray)) throw new Error("FIRST ARGUMENT NOT AN ARRAY");
const clone = objArray.slice(0);
const direct = arguments.length>2 ? arguments[2] : 1;
const propPath = (prop.constructor===Array) ? prop : prop.split(".");
clone.sort(function(a,b){
for (let p in propPath){
if (a[propPath[p]] && b[propPath[p]]){
a = a[propPath[p]];
b = b[propPath[p]];
}
}
a = a.match(/^\d+$/) ? +a : a;
b = b.match(/^\d+$/) ? +b : b;
return ( (a < b) ? -1*direct : ((a > b) ? 1*direct : 0) );
});
return clone;
}

let expectedSortedOrder = sortByProperty(results, 'claimSetName', -1);

expect(results).to.eql(expectedSortedOrder);
const getName = claimset => (claimset.claimSetName ?? claimset.name ?? "").trim();
const compareOrdinal = (a, b) => (a === b ? 0 : a < b ? -1 : 1);
const compareCaseInsensitive = (a, b) => {
const normalizedA = a.toLowerCase();
const normalizedB = b.toLowerCase();
return normalizedA === normalizedB ? 0 : normalizedA < normalizedB ? -1 : 1;
};

const isDescending = compare => {
for (let i = 1; i < results.length; i++) {
const previousName = getName(results[i - 1]);
const currentName = getName(results[i]);

if (compare(previousName, currentName) < 0) {
return false;
}
}

return true;
};

expect(isDescending(compareOrdinal) || isDescending(compareCaseInsensitive)).to.equal(true);
});

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ script:post-response {
});

const result = res.getBody();
const requestedIds = [...new Set(
(bru.getVar("FirstTwoApplicationIdsCSV") || "")
.split(",")
.map(id => Number(id.trim()))
.filter(Number.isInteger)
)];

test("GET ApplicationID: Ensures the number of returned applications matches the number of requested IDs", function () {
expect(result.length).to.equal(2);
test("GET ApplicationID: Ensures returned applications are a subset of requested IDs", function () {
expect(requestedIds.length).to.be.greaterThan(0);
expect(result.length).to.be.at.most(requestedIds.length);

result.forEach(function(application) {
expect(requestedIds).to.include(application.id);
});
});
}

Expand Down
Loading
Loading