Files

204 lines
5.9 KiB
TypeScript
Raw Permalink Normal View History

import { expect, tap } from '@git.zone/tstest/tapbundle';
2025-11-19 20:45:37 +00:00
import { SmartRegistry } from '../ts/index.js';
import { createTestRegistry, createTestTokens } from './helpers/registry.js';
let registry: SmartRegistry;
tap.test('Integration: should create SmartRegistry instance with both protocols', async () => {
registry = await createTestRegistry();
expect(registry).toBeInstanceOf(SmartRegistry);
expect(registry.isInitialized()).toEqual(true);
});
tap.test('Integration: should have both OCI and NPM registries enabled', async () => {
const ociRegistry = registry.getRegistry('oci');
const npmRegistry = registry.getRegistry('npm');
expect(ociRegistry).toBeDefined();
expect(npmRegistry).toBeDefined();
expect(ociRegistry?.getBasePath()).toEqual('/oci');
expect(npmRegistry?.getBasePath()).toEqual('/npm');
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should route OCI requests correctly', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/oci/v2/',
headers: {},
query: {},
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
expect(response.status).toEqual(200);
expect(response.headers['Docker-Distribution-API-Version']).toEqual('registry/2.0');
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should route NPM requests correctly', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/npm/some-package',
headers: {},
query: {},
});
// Will return 404 since package doesn't exist, but should route correctly
expect(response.status).toEqual(404);
expect(response.headers['Content-Type']).toEqual('application/json');
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should return 404 for unknown paths', async () => {
const response = await registry.handleRequest({
method: 'GET',
path: '/unknown/path',
headers: {},
query: {},
});
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
expect(response.status).toEqual(404);
expect(response.body).toHaveProperty('error');
expect((response.body as any).error).toEqual('NOT_FOUND');
});
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
tap.test('Integration: should create and validate tokens', async () => {
const tokens = await createTestTokens(registry);
expect(tokens.npmToken).toBeTypeOf('string');
expect(tokens.ociToken).toBeTypeOf('string');
expect(tokens.userId).toBeTypeOf('string');
// Validate NPM token
const authManager = registry.getAuthManager();
const npmTokenObj = await authManager.validateToken(tokens.npmToken, 'npm');
expect(npmTokenObj).toBeDefined();
expect(npmTokenObj?.type).toEqual('npm');
expect(npmTokenObj?.userId).toEqual(tokens.userId);
// Validate OCI token
const ociTokenObj = await authManager.validateToken(tokens.ociToken, 'oci');
expect(ociTokenObj).toBeDefined();
expect(ociTokenObj?.type).toEqual('oci');
expect(ociTokenObj?.userId).toEqual(tokens.userId);
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should handle authentication properly', async () => {
const authManager = registry.getAuthManager();
// Create a new user
const userId = await authManager.authenticate({
username: 'newuser',
password: 'newpass',
});
expect(userId).toBeTypeOf('string');
expect(userId).toEqual('newuser');
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
// Verify login with correct credentials
const userId2 = await authManager.authenticate({
username: 'newuser',
password: 'newpass',
});
expect(userId2).toEqual('newuser');
// Verify login fails with wrong credentials
const userId3 = await authManager.authenticate({
username: 'newuser',
password: 'wrongpass',
});
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
expect(userId3).toBeNull();
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should handle scoped permissions correctly', async () => {
const authManager = registry.getAuthManager();
// Create user and token with specific scopes
const userId = await authManager.authenticate({
username: 'scopeduser',
password: 'pass',
});
const npmToken = await authManager.createNpmToken(userId!, false);
const tokenObj = await authManager.validateToken(npmToken, 'npm');
// Check authorization for different resources
const canWrite = await authManager.authorize(
tokenObj,
'npm:package:test-package',
'write'
2025-11-19 15:16:20 +00:00
);
2025-11-19 20:45:37 +00:00
expect(canWrite).toEqual(true);
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
const canRead = await authManager.authorize(
tokenObj,
'npm:package:test-package',
'read'
);
expect(canRead).toEqual(true);
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should respect readonly token restrictions', async () => {
const authManager = registry.getAuthManager();
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
const userId = await authManager.authenticate({
username: 'readonlyuser',
password: 'pass',
});
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
const readonlyToken = await authManager.createNpmToken(userId!, true);
const tokenObj = await authManager.validateToken(readonlyToken, 'npm');
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
// Readonly token should allow read
const canRead = await authManager.authorize(
tokenObj,
'npm:package:test-package',
'read'
);
expect(canRead).toEqual(true);
// Readonly token should deny write
const canWrite = await authManager.authorize(
tokenObj,
'npm:package:test-package',
'write'
);
expect(canWrite).toEqual(false);
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
// Readonly token should deny push
const canPush = await authManager.authorize(
tokenObj,
'oci:repository:test-repo',
'push'
);
expect(canPush).toEqual(false);
2025-11-19 15:16:20 +00:00
});
2025-11-19 20:45:37 +00:00
tap.test('Integration: should access storage backend', async () => {
const storage = registry.getStorage();
expect(storage).toBeDefined();
// Test basic storage operations
const testKey = 'test/storage/key';
const testData = Buffer.from('test data', 'utf-8');
await storage.putObject(testKey, testData);
const retrieved = await storage.getObject(testKey);
expect(retrieved).toBeInstanceOf(Buffer);
expect(retrieved?.toString('utf-8')).toEqual('test data');
const exists = await storage.objectExists(testKey);
expect(exists).toEqual(true);
2025-11-19 15:16:20 +00:00
2025-11-19 20:45:37 +00:00
await storage.deleteObject(testKey);
const existsAfterDelete = await storage.objectExists(testKey);
expect(existsAfterDelete).toEqual(false);
});
tap.postTask('cleanup registry', async () => {
if (registry) {
registry.destroy();
}
});
2025-11-19 15:16:20 +00:00
export default tap.start();