import { expect, tap } from '@git.zone/tstest/tapbundle'; 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'); }); tap.test('Integration: should route OCI requests correctly', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/oci/v2/', headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.headers['Docker-Distribution-API-Version']).toEqual('registry/2.0'); }); 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'); }); tap.test('Integration: should return 404 for unknown paths', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/unknown/path', headers: {}, query: {}, }); expect(response.status).toEqual(404); expect(response.body).toHaveProperty('error'); expect((response.body as any).error).toEqual('NOT_FOUND'); }); 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); }); 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'); // 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', }); expect(userId3).toBeNull(); }); 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' ); expect(canWrite).toEqual(true); const canRead = await authManager.authorize( tokenObj, 'npm:package:test-package', 'read' ); expect(canRead).toEqual(true); }); tap.test('Integration: should respect readonly token restrictions', async () => { const authManager = registry.getAuthManager(); const userId = await authManager.authenticate({ username: 'readonlyuser', password: 'pass', }); const readonlyToken = await authManager.createNpmToken(userId!, true); const tokenObj = await authManager.validateToken(readonlyToken, 'npm'); // 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); // Readonly token should deny push const canPush = await authManager.authorize( tokenObj, 'oci:repository:test-repo', 'push' ); expect(canPush).toEqual(false); }); 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); await storage.deleteObject(testKey); const existsAfterDelete = await storage.objectExists(testKey); expect(existsAfterDelete).toEqual(false); }); export default tap.start();