diff --git a/tests/validate-architectures.test.mjs b/tests/validate-architectures.test.mjs index 35e592ba..f8b808bd 100644 --- a/tests/validate-architectures.test.mjs +++ b/tests/validate-architectures.test.mjs @@ -8,6 +8,7 @@ const validRecord = { id: 'acme-platform', title: 'Acme Platform', organization: 'Acme Corp', + sourceUrl: 'https://github.com/cncf/architecture/blob/main/acme-platform.md', assets: ['/img/architectures/acme-platform/diagram.svg'], }; @@ -44,6 +45,72 @@ test('rejects duplicate ids', () => { assert.match(result.stderr, /duplicate id/); }); +test('rejects a record whose sourceUrl is absent', () => { + const { sourceUrl, ...noSource } = validRecord; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([noSource])); + assert.equal(result.status, 1); + assert.match(result.stderr, /sourceUrl must be an https URL/); +}); + +test('rejects a non-https sourceUrl', () => { + const record = { ...validRecord, sourceUrl: 'http://example.com/a' }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /sourceUrl must be an https URL/); +}); + +test('rejects a javascript: sourceUrl', () => { + const record = { ...validRecord, sourceUrl: 'javascript:alert(1)' }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /sourceUrl must be an https URL/); +}); + +test('rejects a sourceUrl that is not a parseable URL', () => { + const record = { ...validRecord, sourceUrl: 'not a url' }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /sourceUrl must be an https URL/); +}); + +test('rejects a sourceUrl that is not a string', () => { + const record = { ...validRecord, sourceUrl: 42 }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /sourceUrl must be an https URL/); +}); + +test('rejects an id that is not a lowercase slug', () => { + const record = { ...validRecord, id: 'Acme_Platform' }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /id must be a lowercase slug/); +}); + +test('rejects an asset outside the architectures prefix', () => { + const record = { ...validRecord, assets: ['/img/logos/acme.svg'] }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /must be a site-absolute path contained in/); +}); + +test('rejects an asset that escapes the architectures prefix with ..', () => { + const record = { + ...validRecord, + assets: ['/img/architectures/../../../etc/passwd'], + }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /must be a site-absolute path contained in/); +}); + +test('rejects an asset that is not a string', () => { + const record = { ...validRecord, assets: [42] }; + const result = runScriptWithFixtures(SCRIPT, catalogFixture([record])); + assert.equal(result.status, 1); + assert.match(result.stderr, /must be a site-absolute path contained in/); +}); + test('rejects assets missing from static/', () => { const fixtures = { 'data/architectures/catalog.json': JSON.stringify([validRecord]),