Skip to content

Commit 4dbcfeb

Browse files
ChaituVRwa0x6e
authored andcommitted
feat: prevent spaces from setting themselves as parent or child (#560)
- Add validation to prevent circular references in space hierarchy - Reject when space.parent equals the space ID - Reject when space.children array contains the space ID - Add comprehensive tests for parent/child validation - Ensure proper error messages for validation failures
1 parent e8c87a2 commit 4dbcfeb

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

src/writer/settings.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ export async function validateSpaceSettings(originalSpace: any) {
2929
delete space.hibernated;
3030
delete space.id;
3131

32+
if (space.parent && space.parent === originalSpace.id) {
33+
return Promise.reject('space cannot be its own parent');
34+
}
35+
36+
if (
37+
space.children &&
38+
Array.isArray(space.children) &&
39+
space.children.includes(originalSpace.id)
40+
) {
41+
return Promise.reject('space cannot be its own child');
42+
}
43+
3244
const schemaIsValid: any = snapshot.utils.validateSchema(snapshot.schemas.space, space, {
3345
spaceType,
3446
snapshotEnv: SNAPSHOT_ENV
@@ -73,6 +85,7 @@ export async function verify(body): Promise<any> {
7385
try {
7486
await validateSpaceSettings({
7587
...msg.payload,
88+
id: msg.space,
7689
deleted: space?.deleted,
7790
turbo: space?.turbo
7891
});

test/unit/writer/settings.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,29 @@ describe('writer/settings', () => {
134134
verify(editedInput({ validation: { name: 'any' }, strategies: [{ name: 'ticket' }] }))
135135
).rejects.toContain('space with ticket requires voting validation');
136136
});
137+
138+
it('rejects if space tries to set itself as parent', async () => {
139+
return expect(verify(editedInput({ parent: 'fabien.eth' }))).rejects.toContain(
140+
'space cannot be its own parent'
141+
);
142+
});
143+
144+
it('rejects if space tries to include itself in children array', async () => {
145+
return expect(
146+
verify(editedInput({ children: ['other-space.eth', 'fabien.eth', 'another-space.eth'] }))
147+
).rejects.toContain('space cannot be its own child');
148+
});
149+
150+
it('accepts valid parent that is not the space itself', async () => {
151+
return expect(verify(editedInput({ parent: 'parent-space.eth' }))).resolves.toBeUndefined();
152+
});
153+
154+
it('accepts valid children array that does not include the space itself', async () => {
155+
return expect(
156+
verify(editedInput({ children: ['child1.eth', 'child2.eth'] }))
157+
).resolves.toBeUndefined();
158+
});
159+
137160
it.todo('rejects if the submitter does not have permission');
138161
it.todo('rejects if the submitter does not have permission to change admin');
139162
const maxStrategiesForNormalSpace = LIMITS['space.default.strategies_limit'];

0 commit comments

Comments
 (0)