feat: integrate XSLT Tools with toolbox portal
This commit is contained in:
80
tests/transformationSecurity.test.ts
Normal file
80
tests/transformationSecurity.test.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { isStylesheetExecutionTrusted } from '../src/transform/stylesheetTrust';
|
||||
import { runTransformation } from '../src/transform/transformService';
|
||||
import {
|
||||
TRANSFORM_LIMITS,
|
||||
assertTransformInputWithinLimits,
|
||||
assertTransformOutputWithinLimits,
|
||||
withTransformationTimeout,
|
||||
} from '../src/transform/transformLimits';
|
||||
|
||||
describe('stylesheet execution trust', () => {
|
||||
it('requires both the exact SHA-256 and the current edit revision', () => {
|
||||
const trust = { hash: 'sha256-a', revision: 4 };
|
||||
expect(isStylesheetExecutionTrusted(trust, 'sha256-a', 4)).toBe(true);
|
||||
expect(isStylesheetExecutionTrusted(trust, 'sha256-b', 4)).toBe(false);
|
||||
expect(isStylesheetExecutionTrusted(trust, 'sha256-a', 5)).toBe(false);
|
||||
expect(isStylesheetExecutionTrusted(null, 'sha256-a', 4)).toBe(false);
|
||||
});
|
||||
|
||||
it.each(['saxon-js-dynamic', 'native-xsltprocessor'] as const)(
|
||||
'refuses the %s service path when authorization does not match',
|
||||
async (engine) => {
|
||||
await expect(
|
||||
runTransformation(
|
||||
{
|
||||
engine,
|
||||
xmlText: '<root/>',
|
||||
xsltText: '<xsl:stylesheet/>',
|
||||
},
|
||||
{
|
||||
trustedStylesheet: { hash: 'not-the-stylesheet-hash', revision: 7 },
|
||||
currentRevision: 7,
|
||||
}
|
||||
)
|
||||
).rejects.toThrow(/review and trust this exact stylesheet/i);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('transformation resource limits', () => {
|
||||
it('rejects oversized XML, XSLT, and result strings', () => {
|
||||
expect(() =>
|
||||
assertTransformInputWithinLimits({
|
||||
engine: 'native-xsltprocessor',
|
||||
xmlText: 'x'.repeat(TRANSFORM_LIMITS.maxXmlBytes + 1),
|
||||
xsltText: '<xsl:stylesheet/>',
|
||||
})
|
||||
).toThrow(/XML input exceeds/i);
|
||||
expect(() =>
|
||||
assertTransformInputWithinLimits({
|
||||
engine: 'saxon-js-dynamic',
|
||||
xmlText: '<root/>',
|
||||
xsltText: 'x'.repeat(TRANSFORM_LIMITS.maxXsltBytes + 1),
|
||||
})
|
||||
).toThrow(/stylesheet exceeds/i);
|
||||
expect(() =>
|
||||
assertTransformOutputWithinLimits({
|
||||
engine: 'saxon-js-dynamic',
|
||||
output: 'x'.repeat(TRANSFORM_LIMITS.maxOutputBytes + 1),
|
||||
diagnostics: [],
|
||||
transformedAt: '2026-01-01T00:00:00.000Z',
|
||||
})
|
||||
).toThrow(/output exceeds/i);
|
||||
});
|
||||
|
||||
it('rejects an asynchronous execution that exceeds its deadline', async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const result = withTransformationTimeout(
|
||||
() => new Promise<never>(() => undefined),
|
||||
25
|
||||
);
|
||||
const rejection = expect(result).rejects.toThrow(/25-millisecond/i);
|
||||
await vi.advanceTimersByTimeAsync(25);
|
||||
await rejection;
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user