Skip to content

Commit 8a7350f

Browse files
committed
fix(V2): enable governance sync in v2 live api tests for ownership coverage
Set V2 GOVERNANCE_BODY_ID in the v2 live api tests job so governance syncs the org list and subscribes to non-home orgs. Add a polling wait for non-home project data between org creation and data tests. Restore the non-home project ownership rejection tests in project-validation that verify PUT/DELETE on synced foreign projects return 400.
1 parent 80e678c commit 8a7350f

2 files changed

Lines changed: 95 additions & 1 deletion

File tree

.github/workflows/tests.yaml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ jobs:
230230
yq -yi '.APP.WALLET_HOST = "https://127.0.0.1:9256"' ~/.chia/mainnet/cadt/config.yaml
231231
yq -yi '.APP.DATALAYER_FILE_SERVER_URL = "https://127.0.0.1:8575"' ~/.chia/mainnet/cadt/config.yaml
232232
yq -yi '.APP.AUTO_MIRROR_EXTERNAL_STORES = false' ~/.chia/mainnet/cadt/config.yaml
233-
yq -yi '.V2.GOVERNANCE.GOVERNANCE_BODY_ID = ""' ~/.chia/mainnet/cadt/config.yaml
233+
yq -yi '.V2.GOVERNANCE.GOVERNANCE_BODY_ID = "4212425c8e053ad58279f1d1a498afec4a1e6b00da356a49ac72780fe13e98e8"' ~/.chia/mainnet/cadt/config.yaml
234234
# Enable V2 for V2 live API tests
235235
yq -yi '.V2.ENABLE = true' ~/.chia/mainnet/cadt/config.yaml
236236
yq -yi '.V1.ENABLE = false' ~/.chia/mainnet/cadt/config.yaml
@@ -482,6 +482,28 @@ jobs:
482482
echo "########################################################"
483483
npm run test:v2:live:wallet-health
484484
echo "########################################################"
485+
echo "Waiting for non-home project from governance sync"
486+
echo "########################################################"
487+
MAX_WAIT=600
488+
ELAPSED=0
489+
while [ "$ELAPSED" -lt "$MAX_WAIT" ]; do
490+
PROJECTS=$(curl -s "http://${TEST_API_HOST:-127.0.0.1}:31310/v2/project?page=1&limit=100" 2>/dev/null || echo "[]")
491+
NON_HOME=$(echo "$PROJECTS" | jq '[
492+
(if type == "object" then .data else . end)[]
493+
| select(.orgUid != null and .orgUid != "'"$(curl -s "http://${TEST_API_HOST:-127.0.0.1}:31310/v2/organizations" 2>/dev/null | jq -r 'to_entries[] | select(.value.isHome == true) | .key')"'")
494+
] | length' 2>/dev/null || echo "0")
495+
if [ "$NON_HOME" -gt 0 ] 2>/dev/null; then
496+
echo "Found $NON_HOME non-home project(s) after ${ELAPSED}s"
497+
break
498+
fi
499+
echo "No non-home projects yet (${ELAPSED}s / ${MAX_WAIT}s)..."
500+
sleep 30
501+
ELAPSED=$((ELAPSED + 30))
502+
done
503+
if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then
504+
echo "WARNING: No non-home projects appeared after ${MAX_WAIT}s. Ownership guard tests will fail."
505+
fi
506+
echo "########################################################"
485507
echo "Running data tests"
486508
echo "########################################################"
487509
npm run test:v2:live:data:short

tests/v2/live-api/project-validation.live.spec.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,36 @@ import {
2525
getInvalidPicklistValue,
2626
} from './data/test-data-generators.js';
2727

28+
const findNonHomeProject = async (request, homeOrgId) => {
29+
let page = 1;
30+
const limit = 100;
31+
32+
while (page <= 10) {
33+
const response = await request
34+
.get('/v2/project')
35+
.query({ page, limit })
36+
.expect(200);
37+
const data = Array.isArray(response.body) ? response.body : (response.body?.data || []);
38+
const nonHomeProject = data.find(record => record.orgUid && record.orgUid !== homeOrgId);
39+
if (nonHomeProject) return nonHomeProject;
40+
41+
const totalPages = response.body?.pageCount || 1;
42+
if (page >= totalPages || data.length < limit) break;
43+
page++;
44+
}
45+
46+
return null;
47+
};
48+
49+
const requireNonHomeProject = async (request, homeOrgId) => {
50+
const nonHomeProject = await findNonHomeProject(request, homeOrgId);
51+
expect(
52+
nonHomeProject,
53+
'Expected at least one synced project from another subscribed organization',
54+
).to.exist;
55+
return nonHomeProject;
56+
};
57+
2858
describe('Project Live API Validation Tests', function () {
2959
this.timeout(600000); // 10 minute timeout
3060
let request;
@@ -178,6 +208,28 @@ describe('Project Live API Validation Tests', function () {
178208
});
179209
});
180210
describe('Step 7: PUT Request Tests', function () {
211+
it('should reject updating a project not owned by the home organization', async function () {
212+
const nonHomeProject = await requireNonHomeProject(request, homeOrgId);
213+
214+
const updateData = {
215+
projectName: `Should Not Update ${Date.now()}`,
216+
projectRegistryName: nonHomeProject.projectRegistryName,
217+
projectId: nonHomeProject.projectId,
218+
};
219+
220+
try {
221+
const response = await request
222+
.put(`/v2/project/${nonHomeProject.cadTrustProjectId}`)
223+
.send(updateData);
224+
225+
expect(response.status).to.equal(400);
226+
expect(response.body.success).to.be.false;
227+
expect(response.body.error).to.include('Restricted data');
228+
} finally {
229+
await clearStagingTable(request);
230+
}
231+
});
232+
181233
it('should update a project', async function () {
182234
// Get ID from createdIds (if available) or query for test records we created
183235
let id = createdIds[0];
@@ -291,6 +343,11 @@ describe('Project Live API Validation Tests', function () {
291343
}
292344
});
293345

346+
it('should include synced project data from another organization', async function () {
347+
const nonHomeProject = await requireNonHomeProject(request, homeOrgId);
348+
expect(nonHomeProject.orgUid).to.not.equal(homeOrgId);
349+
});
350+
294351
it('should support search functionality', async function () {
295352
// Test search if supported by endpoint
296353
const response = await request
@@ -302,6 +359,21 @@ describe('Project Live API Validation Tests', function () {
302359
});
303360
});
304361
describe('Step 9: DELETE Request Tests', function () {
362+
it('should reject deleting a project not owned by the home organization', async function () {
363+
const nonHomeProject = await requireNonHomeProject(request, homeOrgId);
364+
365+
try {
366+
const response = await request
367+
.delete(`/v2/project/${nonHomeProject.cadTrustProjectId}`);
368+
369+
expect(response.status).to.equal(400);
370+
expect(response.body.success).to.be.false;
371+
expect(response.body.error).to.include('Restricted data');
372+
} finally {
373+
await clearStagingTable(request);
374+
}
375+
});
376+
305377
it('should delete all created projects', async function () {
306378
// Query for test projects by orgUid and TEST- prefix
307379
// This works even when DELETE runs in a separate process

0 commit comments

Comments
 (0)