Open
Conversation
- Add new dependencies: opis/json-schema, symfony/security-bundle, symfony/monolog-bundle, move symfony/http-client to require - Create custom JSONB Doctrine type for PostgreSQL JSONB columns - Add security configuration with API key authentication - Add monolog configuration for structured logging - Create ApiKeyAuthenticator, ApiKeyUser, ApiKeyUserProvider for X-API-Key header authentication - Update services.yaml with API_KEY binding - Update .env.example with new environment variables Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Entity Changes: - Add Schema entity for database-stored JSON schemas - Add MetaObjectRevision entity for revision tracking - Modify MetaObject to support multi-tenancy: - Add uuid, objectType, branch, name fields - Add projectId, organizationId for scoping - Add lastUpdated, deletedAt for soft deletes - Add OneToMany relationship to MetaObjectRevision - Data now stored in revisions, not directly on entity Code Cleanup (early removal of deprecated code): - Remove old Data*Controller classes (replaced in Phase 8) - Remove ControllerUtil helper class - Remove deprecated tests for removed controllers - Update MetaObjectFactory for new entity structure - Update MetaObjectRepository to remove ControllerUtil dependency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
DTOs: - CreateRequest: For creating new meta objects - UpdatePatchRequest: For partial updates (PATCH) - UpdatePutRequest: For full replacement (PUT) - MetaObjectResponse: Response DTO with fromEntity/fromArray methods Response Layer: - JsonApiSerializer: Formats responses in JSON:API spec format - Supports single and collection responses - Includes self links and relationships - Proper Content-Type headers - ErrorResponse: Helper for standardized error responses - Methods for common HTTP error codes - Exception ID generation for tracking Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement role-based access control for the metastore service: Authorization components: - Types.php: Role, Action, and Scope enums - Rule.php: Single authorization rule with roles, scopes, and conditions - Policy.php: Policy container for create/update/delete rules - ObjectContext.php: Context about the object being accessed - ScopeHint.php: Hints about project/org scoping - AuthorizationRequest.php: Complete authorization request DTO - PolicyEvaluator.php: Evaluates policies against requests - AuthorizationService.php: Main service for authorization checks ACL parsing: - AclParser.php: Parses ACL rules from schema extensions (supports both x-metastore.acl and x-metastore nested format) New exceptions: - ForbiddenException: 403 responses for unauthorized access - UnauthorizedException: 401 responses for unauthenticated requests - MetaObjectNotFoundException: 404 responses for missing objects Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Core services: - TransactionManager: Database transaction handling wrapper - JsonSchemaValidator: Schema validation using opis/json-schema - Validates data against JSON schemas - Supports schema ID references for $ref resolution - Flattens nested validation errors into readable messages Schema repository: - SchemaRepositoryInterface: Contract for schema data access - SchemaRepository: Doctrine-based implementation - Find default schema by object type - Find schema by object type and version - List schemas by object type - Get all unique object types - Clear default flag for object type Updated services: - SchemaServiceInterface: Enhanced with new methods - getDefaultSchema, getSchemaByVersion, getSchemaData - getFilterableFields, listSchemas, listObjectTypes, schemaExists - SchemaService: Now uses database-backed SchemaRepository instead of file-based schema loading Removed: - SchemaValidatorService: Replaced by JsonSchemaValidator Updated: - services.yaml: Configured interface bindings - SchemaServiceTest: Updated for repository-based service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
MetaObjectRepositoryInterface: - findByUuid, findByUuidString: Find by UUID - findByType: List with multi-tenancy, filtering, pagination - findByNameAndScope: Find by unique name within scope - findRevision, findRevisions: Access revision history - findRevisionsByType: List revisions across all objects - save, saveRevision: Persist entities - softDelete, softDeleteRevision: Soft-delete support - remove: Hard delete (for cleanup) - count: Count with filtering MetaObjectRepository rewrite: - Full multi-tenancy support (projectId, organizationId) - Branch-based filtering - Revision control with soft deletes - JSONB filtering using PostgreSQL operators - Efficient pagination with raw SQL queries - Proper scope resolution for queries Configuration: - Added MetaObjectRepositoryInterface binding in services.yaml Cleanup: - Removed SchemaValidatorServiceTest (service was deleted in Phase 6) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New Controllers:
- HealthCheckController: Health check endpoints
- /health-check: Overall health with DB check
- /health-check/liveness: Basic liveness probe
- /health-check/readiness: Readiness with DB check
- SchemaController: Schema endpoints (public, no auth)
- GET /api/v1/schema: List all object types
- GET /api/v1/schema/{objectType}: Get default schema
- GET /api/v1/schema/{objectType}/{version}: Get specific version
- RepositoryController: Main CRUD (authenticated)
- GET /api/v1/repository/{objectType}: List objects
- POST /api/v1/repository/{objectType}: Create object
- GET /api/v1/repository/{objectType}/{uuid}: Get object
- PATCH /api/v1/repository/{objectType}/{uuid}: Partial update
- PUT /api/v1/repository/{objectType}/{uuid}: Full replacement
- DELETE /api/v1/repository/{objectType}/{uuid}: Soft delete
- GET /api/v1/repository/{objectType}/revisions: List revisions
- GET /api/v1/repository/{objectType}/{uuid}/revisions/{rev}: Get revision
- DELETE /api/v1/repository/{objectType}/{uuid}/revisions/{rev}: Delete revision
Updated Components:
- ExceptionListener: Handle all new exception types with JSON:API errors
- UnauthorizedException, ForbiddenException, MetaObjectNotFoundException
- SchemaNotFoundException, ValidationException, InvalidFilterException
- ErrorResponse: Added conflict() and validationErrorFromRaw() methods
- HomeController: Updated to show new API endpoints and schema service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Commands: - metastore:import-schemas: Import file-based schemas to database - --directory (-d): Source directory for JSON schema files - --version: Version to assign to imported schemas - --force (-f): Force import even if schema exists - --dry-run: Preview without making changes - Extracts description from schema title or description field - Sets imported schema as default for the object type - metastore:verify-db: Verify database structure - Checks database connection - Verifies PostgreSQL version (10+ recommended) - Checks all required tables exist - Validates table columns against expected schema - Reports missing indexes (warnings only) - Provides detailed summary with errors and warnings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Logging: - JsonFormatter: Custom Monolog formatter for JSON logs - Outputs structured JSON with timestamp, level, message, channel - Normalizes exceptions, dates, and objects - Already configured in monolog.yaml for production Configuration: - MetastoreConfig: Centralized configuration class - API key configuration - Debug logging toggle - Pagination settings (default/max page sizes) - Default branch for new objects - Factory method for environment-based initialization Environment: - Updated .env.example with new variables: - METASTORE_DEBUG_LOG - METASTORE_DEFAULT_PAGE_SIZE - METASTORE_MAX_PAGE_SIZE - METASTORE_DEFAULT_BRANCH Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Unit Tests: - PolicyEvaluatorTest: Tests for RBAC policy evaluation - Access allowed when no rules - Access allowed when role matches - Access denied when no matching role - Scope matching (project vs organization) - 'when' condition handling - ProjectID condition evaluation - AclParserTest: Tests for schema ACL parsing - Empty policy for schemas without ACL - Parsing from x-metastore.acl extension key - Parsing from nested x-metastore.acl key - Multiple roles and scopes - 'when' condition parsing - Invalid role/scope handling - Combining singular and plural keys - Parsing all action types - JsonSchemaValidatorTest: Tests for JSON Schema validation - Valid data validation - Required field validation - Type validation - Nested object validation - Array validation - Pattern validation - isValid() convenience method - Enum validation - MinLength/MaxLength validation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cleanup:
- Updated HomeControllerTest to match new title ("Metastore API")
The RFC implementation is complete. All new components pass
PHPStan (level max) and ECS code style checks.
Summary of implementation:
- New API routes at /api/v1/repository/{objectType}
- Simple API Key authentication (X-API-Key header)
- RBAC authorization with schema-based ACL policies
- Database-stored schemas with version support
- Multi-tenant MetaObject with revision history
- Soft deletes for objects and revisions
- JSON:API compliant responses
- Schema migration command for importing file-based schemas
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Symfony's service autowiring expected a class named "Types" but found enums. Split the file into separate Role.php, Action.php, and Scope.php files so each enum is in its own file matching its class name. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…egration - Added Unit testsuite to phpunit.xml.dist - Removed empty Integration testsuite that was causing CI failure - Removed empty tests/Integration directory Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test was using default ObjectContext with projectId '123', but normalizeHint() sets isProjectScoped=true when object has a non-empty projectId. Fixed by providing ObjectContext with empty projectId. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added 'doctrine:schema:create' step to CI workflow before running tests - Updated RefreshDatabaseForWebTestTrait to truncate all entity tables (meta_object_revisions, meta_objects, schemas) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ementation Add 176 new unit tests and integration tests covering: - Authorization: RuleTest, PolicyTest, AuthorizationServiceTest - Security: ApiKeyUserTest, ApiKeyUserProviderTest, ApiKeyAuthenticatorTest - Response: ErrorResponseTest, JsonApiSerializerTest - DTOs: CreateRequestTest, UpdatePatchRequestTest, UpdatePutRequestTest, MetaObjectResponseTest - Services: TransactionManagerTest - Config: MetastoreConfigTest - Logging: JsonFormatterTest - EventListener: ExceptionListenerTest - API Controllers: RepositoryControllerTest, SchemaControllerTest, HealthCheckControllerTest - Commands: ImportSchemasCommandTest, VerifyDatabaseCompatibilityCommandTest - Test infrastructure: SchemaFactory Total unit tests increased from 52 to 228 (338% increase). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add API_KEY=test-api-key-for-ci to .env.ci and .env.test for consistent test environment - Update RepositoryControllerTest to use the test API key - Rename --version option to --schema-version in ImportSchemasCommand to avoid conflict with Symfony Console's built-in --version option - Update ImportSchemasCommandTest to use renamed option Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The .env file loading was not reliably setting API_KEY in CI. Adding it directly to phpunit.xml.dist ensures the environment variable is set before tests run. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of hardcoding the API key, retrieve it from the ApiKeyAuthenticator service using reflection. This ensures tests always use the same key the authenticator expects, regardless of environment configuration. - Add services_test.yaml to make ApiKeyAuthenticator public for tests - Update RepositoryControllerTest to get API key from container Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The service definition was missing the constructor argument, causing "Too few arguments" error in CI. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix getLatestRevision() to find highest revision number instead of using first() which fails after in-memory additions - Fix getNextRevisionNumber() with same issue - Fix testListReturnsMetaObjects to include X-Project-ID header matching the projectId of created objects Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add phpstan.neon with ignore patterns for common test-related type issues at max level. Update test files with proper type assertions for json_decode return values and container service retrieval. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic formatting fixes including array formatting and consistent code style across test files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.