# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - Added transparent PyPI proxy implementing PEP 503 Simple API (#108) - `GET /pypi/simple/` - package index (proxied from upstream) - `GET /pypi/simple/{package}/` - version list with rewritten download links - `GET /pypi/simple/{package}/{filename}` - download with automatic caching - Allows `pip install --index-url https://orchard.../pypi/simple/ ` - Artifacts cached on first access through configured upstream sources - Added `POST /api/v1/cache/resolve` endpoint to cache packages by coordinates instead of URL (#108) ### Changed - Upstream sources table text is now centered under column headers (#108) - ENV badge now appears inline with source name instead of separate column (#108) - Test and Edit buttons now have more prominent button styling (#108) - Reduced footer padding for cleaner layout (#108) ### Fixed - Fixed purge_seed_data crash when deleting access permissions - was comparing UUID to VARCHAR column (#107) ### Changed - Upstream source connectivity test no longer follows redirects, fixing "Exceeded maximum allowed redirects" error with Artifactory proxies (#107) - Test runs automatically after saving a new or updated upstream source (#107) - Test status now shows as colored dots (green=success, red=error) instead of text badges (#107) - Clicking red dot shows error details in a modal (#107) - Source name column no longer wraps text for better table layout (#107) - Renamed "Cache Management" page to "Upstream Sources" (#107) - Moved Delete button from table row to edit modal for cleaner table layout (#107) ### Removed - Removed `is_public` field from upstream sources - all sources are now treated as internal/private (#107) - Removed `allow_public_internet` (air-gap mode) setting from cache settings - not needed for enterprise proxy use case (#107) - Removed seeding of public registry URLs (npm-public, pypi-public, maven-central, docker-hub) (#107) - Removed "Public" badge and checkbox from upstream sources UI (#107) - Removed "Allow Public Internet" toggle from cache settings UI (#107) - Removed "Global Settings" section from cache management UI - auto-create system projects is always enabled (#107) - Removed unused CacheSettings frontend types and API functions (#107) ### Added - Added `ORCHARD_PURGE_SEED_DATA` environment variable support to stage helm values to remove seed data from long-running deployments (#107) - Added frontend system projects visual distinction (#105) - "Cache" badge for system projects in project list - "System Cache" badge on project detail page - Added `is_system` field to Project type - Added frontend admin page for upstream sources and cache settings (#75) - New `/admin/cache` page accessible from user menu (admin only) - Upstream sources table with create/edit/delete/test connectivity - Cache settings section with air-gap mode and auto-create system projects toggles - Visual indicators for env-defined sources (locked, cannot be modified) - Environment variable override badges when settings are overridden - API client functions for all cache admin operations - Added environment variable overrides for cache configuration (#74) - `ORCHARD_CACHE_ALLOW_PUBLIC_INTERNET` - Override allow_public_internet (air-gap mode) - `ORCHARD_CACHE_AUTO_CREATE_SYSTEM_PROJECTS` - Override auto_create_system_projects - `ORCHARD_UPSTREAM__{NAME}__*` - Define upstream sources via env vars - Env-defined sources appear in API with `source: "env"` marker - Env-defined sources cannot be modified/deleted via API (400 error) - Cache settings response includes `*_env_override` fields when overridden - 7 unit tests for env var parsing and configuration - Added Global Cache Settings Admin API (#73) - `GET /api/v1/admin/cache-settings` - Retrieve current cache settings - `PUT /api/v1/admin/cache-settings` - Update cache settings (partial updates) - Admin-only access with audit logging - Controls `allow_public_internet` (air-gap mode) and `auto_create_system_projects` - 7 integration tests for settings management - Added Upstream Sources Admin API for managing cache sources (#72) - `GET /api/v1/admin/upstream-sources` - List sources with filtering - `POST /api/v1/admin/upstream-sources` - Create source with auth configuration - `GET /api/v1/admin/upstream-sources/{id}` - Get source details - `PUT /api/v1/admin/upstream-sources/{id}` - Update source (partial updates) - `DELETE /api/v1/admin/upstream-sources/{id}` - Delete source - `POST /api/v1/admin/upstream-sources/{id}/test` - Test connectivity - Admin-only access with audit logging - Credentials never exposed (only has_password/has_headers flags) - 13 integration tests for all CRUD operations - Added system project restrictions and management (#71) - System projects (`_npm`, `_pypi`, etc.) cannot be deleted (returns 403) - System projects cannot be made private (must remain public) - `GET /api/v1/system-projects` endpoint to list all system cache projects - 5 integration tests for system project restrictions - Added Cache API endpoint for fetching and storing artifacts from upstream URLs (#70) - `POST /api/v1/cache` endpoint to cache artifacts from upstream registries - URL parsing helpers to extract package name/version from npm, PyPI, Maven URLs - Automatic system project creation (`_npm`, `_pypi`, `_maven`, etc.) - URL-to-artifact provenance tracking via `cached_urls` table - Optional user project cross-referencing for custom organization - Cache hit returns existing artifact without re-fetching - Air-gap mode enforcement (blocks public URLs when disabled) - Hash verification for downloaded artifacts - 21 unit tests for URL parsing and cache endpoint - Added HTTP client for fetching artifacts from upstream sources (#69) - `UpstreamClient` class in `backend/app/upstream.py` with streaming downloads - SHA256 hash computation while streaming (doesn't load large files into memory) - Auth support: none, basic auth, bearer token, API key (custom headers) - URL-to-source matching by URL prefix with priority ordering - Configuration options: timeouts, retries with exponential backoff, redirect limits, max file size - Air-gap mode enforcement via `allow_public_internet` setting - Response header capture for provenance tracking - Proper error handling with custom exception types - Connection test method for upstream source validation - 33 unit tests for client functionality - Added upstream artifact caching schema for hermetic builds (#68) - `upstream_sources` table for configuring upstream registries (npm, PyPI, Maven, etc.) - `cache_settings` table for global settings including air-gap mode - `cached_urls` table for URL-to-artifact provenance tracking - `is_system` column on projects for system cache projects (_npm, _pypi, etc.) - Support for multiple auth types: none, basic auth, bearer token, API key - Fernet encryption for credentials using `ORCHARD_CACHE_ENCRYPTION_KEY` - Default upstream sources seeded (npm-public, pypi-public, maven-central, docker-hub) - disabled by default - Migration `010_upstream_caching.sql` - Added team-based multi-tenancy for organizing projects and collaboration (#88-#104) - Teams serve as organizational containers for projects - Users can belong to multiple teams with different roles (owner, admin, member) - Projects can optionally belong to a team - Added database schema for teams (#88): - `teams` table with id, name, slug, description, settings, timestamps - `team_memberships` table mapping users to teams with roles - `team_id` column on projects table for team association - Migrations `009_teams.sql` and `009b_migrate_projects.sql` - Added Team and TeamMembership ORM models with relationships (#89) - Added TeamAuthorizationService for team-level access control (#90): - Team owner/admin gets admin access to all team projects - Team member gets read access to team projects (upgradeable by explicit permission) - Role hierarchy: owner > admin > member - Added Team API endpoints (#92, #93, #94, #95): - `GET /api/v1/teams` - List teams user belongs to (paginated) - `POST /api/v1/teams` - Create team (creator becomes owner) - `GET /api/v1/teams/{slug}` - Get team details - `PUT /api/v1/teams/{slug}` - Update team (requires admin) - `DELETE /api/v1/teams/{slug}` - Delete team (requires owner) - `GET /api/v1/teams/{slug}/members` - List team members - `POST /api/v1/teams/{slug}/members` - Add member (requires admin) - `PUT /api/v1/teams/{slug}/members/{username}` - Update member role - `DELETE /api/v1/teams/{slug}/members/{username}` - Remove member - `GET /api/v1/teams/{slug}/projects` - List team projects (paginated) - Updated project creation to support optional team assignment (#95) - Updated project responses to include team info (team_id, team_slug, team_name) - Added frontend team management (#97-#104): - TeamContext provider for managing current team selection - TeamSelector dropdown component (persists selection in localStorage) - Teams list page at `/teams` - Team dashboard page at `/teams/{slug}` with inline project creation - Team settings page at `/teams/{slug}/settings` - Team members page at `/teams/{slug}/members` - Teams navigation link in header (authenticated users only) - Updated seed data to create a "Demo Team" and assign all seed projects to it - Added TypeScript types and API client functions for teams - Access management now shows team-based permissions alongside explicit permissions - Team-based access displayed as read-only with "Source" column indicating origin - Team members with access show team slug and role - Added integration tests for team CRUD, membership, and project operations - Redesigned teams portal with modern card-based layout - Card grid view with team avatar, name, slug, role badge, and stats - Stats bar showing total teams, owned teams, and total projects - Search functionality for filtering teams (appears when >3 teams) - Empty states for no teams and no search results - Added user autocomplete component for team member invitations - `GET /api/v1/users/search` endpoint for username prefix search - Dropdown shows matching users as you type - Keyboard navigation support (arrow keys, enter, escape) - Debounced search to reduce API calls - Added unit tests for TeamAuthorizationService - Added `ORCHARD_ADMIN_PASSWORD` environment variable to configure initial admin password (#87) - When set, admin user is created with the specified password (no password change required) - When not set, defaults to `changeme123` and requires password change on first login - Added Helm chart support for admin password via multiple sources (#87): - `orchard.auth.adminPassword` - plain value (creates K8s secret) - `orchard.auth.existingSecret` - reference existing K8s secret - `orchard.auth.secretsManager` - AWS Secrets Manager integration - Added `.env.example` template for local development (#87) - Added `.env` file support in docker-compose.local.yml (#87) - Added Project Settings page accessible to project admins (#65) - General settings section for editing description and visibility - Access Management section (moved from project page) - Danger Zone section with inline delete confirmation requiring project name - Settings button (gear icon) on project page header for admins - Added artifact dependency management system (#76, #77, #78, #79, #80, #81) - `artifact_dependencies` table with version/tag constraints and check constraints - `ArtifactDependency` SQLAlchemy model with indexes for fast lookups - Ensure file parsing (`orchard.ensure` YAML format) during artifact upload - Circular dependency detection at upload time (rejected with 400) - Dependency conflict detection at resolution time (409 with conflict details) - Added dependency API endpoints (#78, #79): - `GET /api/v1/artifact/{artifact_id}/dependencies` - Get dependencies by artifact ID - `GET /api/v1/project/{project}/{package}/+/{ref}/dependencies` - Get dependencies by ref - `GET /api/v1/project/{project}/{package}/reverse-dependencies` - Get reverse dependencies (paginated) - `GET /api/v1/project/{project}/{package}/+/{ref}/resolve` - Resolve full dependency tree - Added dependency resolution with topological sorting (#79) - Returns flat list of all artifacts needed in dependency order - Includes download URLs, sizes, and version info for each artifact - Added frontend dependency visualization (#84, #85, #86): - Dependencies section on package page showing direct dependencies for selected tag - Tag/version selector to switch between artifacts - "Used By" section showing reverse dependencies with pagination - Interactive dependency graph modal with: - Tree visualization with collapsible nodes - Zoom (mouse wheel + buttons) and pan (click-drag) - Click to navigate to package - Hover tooltip with package details - Error display for circular dependencies and conflicts - Added migration `008_artifact_dependencies.sql` for dependency schema - Added `dependencies.py` module with parsing, validation, and resolution logic - Added comprehensive integration tests for all dependency features ### Changed - Added pre-test stage reset to ensure known environment state before integration tests (#54) - Upload endpoint now accepts optional `ensure` file parameter for declaring dependencies - Updated upload API documentation with ensure file format and examples - Converted teams list and team projects to use DataTable component for consistent styling - Centered team members and team settings page content - Added orchard logo icon and dot separator to footer ### Fixed - Fixed dark theme styling for team pages - modals, forms, and dropdowns now use correct theme variables - Fixed UserAutocomplete and TeamSelector dropdown backgrounds for dark theme ## [0.5.1] - 2026-01-23 ### Changed - Simplified tag pipeline to only run deploy and smoke tests (image already built on main) (#54) ### Fixed - Fixed production CI deployment namespace to use correct `orch-namespace` (#54) - Added gitleaks config to allowlist test files from secret scanning (#54) ## [0.5.0] - 2026-01-23 ### Added - Added factory reset endpoint `POST /api/v1/admin/factory-reset` for test environment cleanup (#54) - Requires admin authentication and `X-Confirm-Reset: yes-delete-all-data` header - Drops all database tables, clears S3 bucket, reinitializes schema, re-seeds default data - CI pipeline automatically calls this after integration tests on stage - Added `delete_all()` method to storage backend for bulk S3 object deletion (#54) - Added AWS Secrets Manager CSI driver support for database credentials (#54) - Added SecretProviderClass template for Secrets Manager integration (#54) - Added IRSA service account annotations for prod and stage environments (#54) - Added comprehensive upload/download tests for size boundaries (1B to 1GB) (#38) - Added concurrent upload/download tests (2, 5, 10 parallel operations) (#38) - Added data integrity tests (binary, text, unicode, compressed content) (#38) - Added chunk boundary tests for edge cases (#38) - Added `@pytest.mark.large` and `@pytest.mark.concurrent` test markers (#38) - Added `generate_content()` and `generate_content_with_hash()` test helpers (#38) - Added `sized_content` fixture for generating test content of specific sizes (#38) - Added upload API tests: upload without tag, artifact creation verification, S3 object creation (#38) - Added download API tests: tag: prefix resolution, 404 for nonexistent project/package/artifact (#38) - Added download header tests: Content-Type, Content-Length, Content-Disposition, ETag, X-Checksum-SHA256 (#38) - Added error handling tests: timeout behavior, checksum validation, resource cleanup, graceful error responses (#38) - Added version API tests: version creation, auto-detection, listing, download by version prefix (#38) - Added integrity verification tests: round-trip hash verification, client-side verification workflow, size variants (1KB-10MB) (#40) - Added consistency check endpoint tests with response format validation (#40) - Added corruption detection tests: bit flip, truncation, appended content, size mismatch, missing S3 objects (#40) - Added Digest header tests (RFC 3230) and verification mode tests (#40) - Added integrity verification documentation (`docs/integrity-verification.md`) (#40) - Added conditional request support for downloads (If-None-Match, If-Modified-Since) returning 304 Not Modified (#42) - Added caching headers to downloads: Cache-Control (immutable), Last-Modified (#42) - Added 416 Range Not Satisfiable response for invalid range requests (#42) - Added download completion logging with bytes transferred and throughput (#42) - Added client disconnect handling during streaming downloads (#42) - Added streaming download tests: range requests, conditional requests, caching headers, download resume (#42) - Added upload duration and throughput metrics (`duration_ms`, `throughput_mbps`) to upload response (#43) - Added upload progress logging for large files (hash computation and multipart upload phases) (#43) - Added client disconnect handling during uploads with proper cleanup (#43) - Added upload progress tracking endpoint `GET /upload/{upload_id}/progress` for resumable uploads (#43) - Added large file upload tests (10MB, 100MB, 1GB) with multipart upload verification (#43) - Added upload cancellation and timeout handling tests (#43) - Added comprehensive API documentation for upload endpoints with curl, Python, and JavaScript examples (#43) - Added `package_versions` table for immutable version tracking separate from mutable tags (#56) - Versions are set at upload time via explicit `version` parameter or auto-detected from filename/metadata - Version detection priority: explicit parameter > package metadata > filename pattern - Versions are immutable once created (unlike tags which can be moved) - Added version API endpoints (#56): - `GET /api/v1/project/{project}/{package}/versions` - List all versions for a package - `GET /api/v1/project/{project}/{package}/versions/{version}` - Get specific version details - `DELETE /api/v1/project/{project}/{package}/versions/{version}` - Delete a version (admin only) - Added version support to upload endpoint via `version` form parameter (#56) - Added `version:X.Y.Z` prefix for explicit version resolution in download refs (#56) - Added version field to tag responses (shows which version the artifact has, if any) (#56) - Added migration `007_package_versions.sql` with ref_count triggers and data migration from semver tags (#56) - Added production deployment job triggered by semantic version tags (v1.0.0) with manual approval gate (#63) - Added production Helm values file with persistence enabled (20Gi PostgreSQL, 100Gi MinIO) (#63) - Added integration tests for production deployment (#63) - Added GitLab CI pipeline for feature branch deployments to dev namespace (#51) - Added `deploy_feature` job with dynamic hostnames and unique release names (#51) - Added `cleanup_feature` job with `on_stop` for automatic cleanup on merge (#51) - Added `values-dev.yaml` Helm values for lightweight ephemeral environments (#51) - Added main branch deployment to stage environment (#51) - Added post-deployment integration tests (#51) - Added internal proxy configuration for npm, pip, helm, and apt (#51) ### Changed - Configured stage and prod to use AWS RDS instead of PostgreSQL subchart (#54) - Configured stage and prod to use AWS S3 instead of MinIO subchart (#54) - Changed prod deployment from manual to automatic on version tags (#54) - Updated S3 client to support IRSA credentials when no explicit keys provided (#54) - Changed prod image pullPolicy to Always (#54) - Added proxy-body-size annotation to prod ingress for large uploads (#54) - CI integration tests now run full pytest suite (~350 tests) against deployed environment instead of 3 smoke tests - CI production deployment uses lightweight smoke tests only (no test data creation in prod) - CI pipeline improvements: shared pip cache, `interruptible` flag on test jobs, retry on integration tests - Simplified deploy verification to health check only (full checks done by integration tests) - Extracted environment URLs to global variables for maintainability - Made `cleanup_feature` job standalone (no longer inherits deploy template dependencies) - Renamed `integration_test_prod` to `smoke_test_prod` for clarity - Updated download ref resolution to check versions before tags (version → tag → artifact ID) (#56) - Deploy jobs now require all security scans to pass before deployment (added test_image, app_deps_scan, cve_scan, cve_sbom_analysis, app_sbom_analysis to dependencies) (#63) - Increased deploy job timeout from 5m to 10m (#63) - Added `--atomic` flag to Helm deployments for automatic rollback on failure - Adjusted dark mode color palette to use lighter background tones for better readability and reduced eye strain (#52) - Replaced project card grid with sortable data table on Home page for better handling of large project lists - Replaced package card grid with sortable data table on Project page for consistency - Replaced SortDropdown with table header sorting on Package page for consistency - Enabled sorting on supported table columns (name, created, updated) via clickable headers - Updated browser tab title to "Orchard" with custom favicon - Improved pod naming: Orchard pods now named `orchard-{env}-server-*` for clarity (#51) ### Fixed - Fixed factory reset not creating default admin user after reset (#60) - Admin user was only created at server startup, not after factory reset - CI reset job would fail to login because admin user didn't exist - Improved reset_stage CI job reliability (#60) - Added application-level retry logic (3 attempts with 5s delay) - Added job-level retry for transient failures - Fixed httpx client to use proper context manager - Increased timeout to 120s for reset operations - Fixed CI integration test rate limiting: added configurable `ORCHARD_LOGIN_RATE_LIMIT` env var, relaxed to 1000/minute for dev/stage - Fixed duplicate `TestSecurityEdgeCases` class definition in test_auth_api.py - Fixed integration tests auth: session-scoped client, configurable credentials via env vars, fail-fast on auth errors - Fixed 413 Request Entity Too Large errors on uploads by adding `proxy-body-size: "0"` nginx annotation to Orchard ingress - Fixed CI tests that require direct S3 access: added `@pytest.mark.requires_direct_s3` marker and excluded from CI - Fixed ref_count triggers not being created: added auto-migration for tags ref_count trigger functions - Fixed Content-Disposition header encoding for non-ASCII filenames using RFC 5987 (#38) - Fixed deploy jobs running even when tests or security scans fail (changed rules from `when: always` to `when: on_success`) (#63) - Fixed python_tests job not using internal PyPI proxy (#63) - Fixed `cleanup_feature` job failing when branch is deleted (`GIT_STRATEGY: none`) (#51) - Fixed gitleaks false positives with fingerprints for historical commits (#51) - Fixed integration tests running when deploy fails (`when: on_success`) (#51) - Fixed static file serving for favicon and other files in frontend dist root - Fixed deploy jobs running when secrets scan fails (added `secrets` to deploy dependencies) - Fixed dev environment memory requests to equal limits per cluster Kyverno policy - Fixed init containers missing resource limits (Kyverno policy compliance) - Fixed Python SyntaxWarning for invalid escape sequence in database migration regex pattern ### Removed - Removed unused `store_streaming()` method from storage.py (#51) - Disabled PostgreSQL subchart for stage and prod environments (#54) - Disabled MinIO subchart for stage and prod environments (#54) ## [0.4.0] - 2026-01-12 ### Added - Added user authentication system with session-based login (#50) - `users` table with password hashing (bcrypt), admin flag, active status - `sessions` table for web login sessions (24-hour expiry) - `auth_settings` table for future OIDC configuration - Default admin user created on first boot (username: admin, password: admin) - Added auth API endpoints (#50) - `POST /api/v1/auth/login` - Login with username/password - `POST /api/v1/auth/logout` - Logout and clear session - `GET /api/v1/auth/me` - Get current user info - `POST /api/v1/auth/change-password` - Change own password - Added API key management with user ownership (#50) - `POST /api/v1/auth/keys` - Create API key (format: `orch_`) - `GET /api/v1/auth/keys` - List user's API keys - `DELETE /api/v1/auth/keys/{id}` - Revoke API key - Added `owner_id`, `scopes`, `description` columns to `api_keys` table - Added admin user management endpoints (#50) - `GET /api/v1/admin/users` - List all users - `POST /api/v1/admin/users` - Create user - `GET /api/v1/admin/users/{username}` - Get user details - `PUT /api/v1/admin/users/{username}` - Update user (admin/active status) - `POST /api/v1/admin/users/{username}/reset-password` - Reset password - Added `auth.py` module with AuthService class and FastAPI dependencies (#50) - Added auth schemas: LoginRequest, LoginResponse, UserResponse, APIKeyResponse (#50) - Added migration `006_auth_tables.sql` for auth database tables (#50) - Added frontend Login page with session management (#50) - Added frontend API Keys management page (#50) - Added frontend Admin Users page (admin-only) (#50) - Added AuthContext for frontend session state (#50) - Added user menu to Layout header with login/logout (#50) - Added 15 integration tests for auth system (#50) - Added reusable `DragDropUpload` component for artifact uploads (#8) - Drag-and-drop file selection with visual feedback - Click-to-browse fallback - Multiple file upload support with queue management - Real-time progress indicators with speed and ETA - File type and size validation (configurable) - Concurrent upload handling (configurable max concurrent) - Automatic retry with exponential backoff for network errors - Individual file status (pending, uploading, complete, failed) - Retry and remove actions per file - Auto-dismiss success messages after 5 seconds - Integrated DragDropUpload into PackagePage replacing basic file input (#8) - Added frontend testing infrastructure with Vitest and React Testing Library (#14) - Configured Vitest for React/TypeScript with jsdom - Added 24 unit tests for DragDropUpload component - Tests cover: rendering, drag-drop events, file validation, upload queue, progress, errors - Added chunked upload support for large files (#9) - Files >100MB automatically use chunked upload API (10MB chunks) - Client-side SHA256 hash computation via Web Crypto API - localStorage persistence for resume after browser close - Deduplication check at upload init phase - Added offline detection and network resilience (#12) - Automatic pause when browser goes offline - Auto-resume when connection restored - Offline banner UI with status message - XHR abort on network loss to prevent hung requests - Added download by artifact ID feature (#10) - Direct artifact ID input field on package page - Hex-only input validation with character count - File size and filename displayed in tag list - Added backend security tests (#15) - Path traversal prevention tests for upload/download - Malformed request handling tests - Checksum validation tests - 10 new security-focused integration tests - Added download verification with `verify` and `verify_mode` query parameters (#26) - `?verify=true&verify_mode=pre` - Pre-verification: verify before streaming (guaranteed no corrupt data) - `?verify=true&verify_mode=stream` - Streaming verification: verify while streaming (logs error if mismatch) - Added checksum response headers to all download endpoints (#27) - `X-Checksum-SHA256` - SHA256 hash of the artifact - `X-Content-Length` - File size in bytes - `X-Checksum-MD5` - MD5 hash (if available) - `ETag` - Artifact ID (SHA256) - `Digest` - RFC 3230 format sha-256 hash (base64) - `X-Verified` - Verification status (true/false/pending) - Added `checksum.py` module with SHA256 utilities (#26) - `compute_sha256()` and `compute_sha256_stream()` functions - `HashingStreamWrapper` for incremental hash computation - `VerifyingStreamWrapper` for stream verification - `verify_checksum()` and `verify_checksum_strict()` functions - `ChecksumMismatchError` exception with context - Added `get_verified()` and `get_stream_verified()` methods to storage layer (#26) - Added `logging_config.py` module with structured logging (#28) - JSON logging format for production - Request ID tracking via context variables - Verification failure logging with full context - Added `log_level` and `log_format` settings to configuration (#28) - Added 62 unit tests for checksum utilities and verification (#29) - Added 17 integration tests for download verification API (#29) - Added global artifacts endpoint `GET /api/v1/artifacts` with project/package/tag/size/date filters (#18) - Added global tags endpoint `GET /api/v1/tags` with project/package/search/date filters (#18) - Added wildcard pattern matching (`*`) for tag filters across all endpoints (#18) - Added comma-separated multi-value support for tag filters (#18) - Added `search` parameter to `/api/v1/uploads` for filename search (#18) - Added `tag` filter to `/api/v1/uploads` endpoint (#18) - Added `sort` and `order` parameters to `/api/v1/uploads` endpoint (#18) - Added `min_size` and `max_size` filters to package artifacts endpoint (#18) - Added `sort` and `order` parameters to package artifacts endpoint (#18) - Added `from` and `to` date filters to package tags endpoint (#18) - Added `GlobalArtifactResponse` and `GlobalTagResponse` schemas (#18) - Added S3 object verification before database commit during upload (#19) - Added S3 object cleanup on database commit failure (#19) - Added upload duration tracking (`duration_ms` field) (#19) - Added `User-Agent` header capture during uploads (#19) - Added `X-Checksum-SHA256` header support for client-side checksum verification (#19) - Added `status`, `error_message`, `client_checksum` columns to uploads table (#19) - Added `upload_locks` table for future concurrent upload conflict detection (#19) - Added consistency check endpoint `GET /api/v1/admin/consistency-check` (#19) - Added `PUT /api/v1/projects/{project}` endpoint for project updates with audit logging (#20) - Added `PUT /api/v1/project/{project}/packages/{package}` endpoint for package updates with audit logging (#20) - Added `artifact.download` audit logging to download endpoint (#20) - Added `ProjectHistory` and `PackageHistory` models with database triggers (#20) - Added migration `004_history_tables.sql` for project/package history (#20) - Added migration `005_upload_enhancements.sql` for upload status tracking (#19) - Added 9 integration tests for global artifacts/tags endpoints (#18) - Added global uploads query endpoint `GET /api/v1/uploads` with project/package/user/date filters (#18) - Added project-level uploads endpoint `GET /api/v1/project/{project}/uploads` (#18) - Added `has_more` field to pagination metadata for easier pagination UI (#18) - Added `upload_id`, `content_type`, `original_name`, `created_at` fields to upload response (#19) - Added audit log API endpoints with filtering and pagination (#20) - `GET /api/v1/audit-logs` - list all audit logs with action/resource/user/date filters - `GET /api/v1/projects/{project}/audit-logs` - project-scoped audit logs - `GET /api/v1/project/{project}/{package}/audit-logs` - package-scoped audit logs - Added upload history API endpoints (#20) - `GET /api/v1/project/{project}/{package}/uploads` - list upload events for a package - `GET /api/v1/artifact/{id}/uploads` - list all uploads of a specific artifact - Added artifact provenance endpoint `GET /api/v1/artifact/{id}/history` (#20) - Returns full artifact history including packages, tags, and upload events - Added audit logging for project.create, package.create, tag.create, tag.update, artifact.upload actions (#20) - Added `AuditLogResponse`, `UploadHistoryResponse`, `ArtifactProvenanceResponse` schemas (#20) - Added `TagHistoryDetailResponse` schema with artifact metadata (#20) - Added 31 integration tests for audit log, history, and upload query endpoints (#22) ### Changed - Standardized audit action naming to `{entity}.{action}` pattern (project.delete, package.delete, tag.delete) (#20) - Added `StorageBackend` protocol/interface for backend-agnostic storage (#33) - Added `health_check()` method to storage backend with `/health` endpoint integration (#33) - Added `verify_integrity()` method for post-upload hash validation (#33) - Added S3 configuration options: `s3_verify_ssl`, `s3_connect_timeout`, `s3_read_timeout`, `s3_max_retries` (#33) - Added `S3StorageUnavailableError` and `HashCollisionError` exception types (#33) - Added hash collision detection by comparing file sizes during deduplication (#33) - Added garbage collection endpoint `POST /api/v1/admin/garbage-collect` for orphaned artifacts (#36) - Added orphaned artifacts listing endpoint `GET /api/v1/admin/orphaned-artifacts` (#36) - Added global storage statistics endpoint `GET /api/v1/stats` (#34) - Added storage breakdown endpoint `GET /api/v1/stats/storage` (#34) - Added deduplication metrics endpoint `GET /api/v1/stats/deduplication` (#34) - Added per-project statistics endpoint `GET /api/v1/projects/{project}/stats` (#34) - Added per-package statistics endpoint `GET /api/v1/project/{project}/packages/{package}/stats` (#34) - Added per-artifact statistics endpoint `GET /api/v1/artifact/{id}/stats` (#34) - Added cross-project deduplication endpoint `GET /api/v1/stats/cross-project` (#34) - Added timeline statistics endpoint `GET /api/v1/stats/timeline` with daily/weekly/monthly periods (#34) - Added stats export endpoint `GET /api/v1/stats/export` with JSON/CSV formats (#34) - Added summary report endpoint `GET /api/v1/stats/report` with markdown/JSON formats (#34) - Added Dashboard page at `/dashboard` with storage and deduplication visualizations (#34) - Added pytest infrastructure with mock S3 client for unit testing (#35) - Added unit tests for SHA256 hash calculation (#35) - Added unit tests for duplicate detection and deduplication behavior (#35) - Added integration tests for upload scenarios and ref_count management (#35) - Added integration tests for S3 verification and failure cleanup (#35) - Added integration tests for all stats endpoints (#35) - Added integration tests for cascade deletion ref_count behavior (package/project delete) (#35) - Added integration tests for tag update ref_count adjustments (#35) - Added integration tests for garbage collection endpoints (#35) - Added integration tests for file size validation (#35) - Added test dependencies to requirements.txt (pytest, pytest-asyncio, pytest-cov, httpx, moto) (#35) - Added `ORCHARD_MAX_FILE_SIZE` config option (default: 10GB) for upload size limits (#37) - Added `ORCHARD_MIN_FILE_SIZE` config option (default: 1 byte, rejects empty files) (#37) - Added file size validation to upload and resumable upload endpoints (#37) - Added comprehensive deduplication design document (`docs/design/deduplication-design.md`) (#37) ### Fixed - Fixed Helm chart `minio.ingress` conflicting with Bitnami MinIO subchart by renaming to `minioIngress` (#48) - Fixed JSON report serialization error for Decimal types in `GET /api/v1/stats/report` (#34) - Fixed resumable upload double-counting ref_count when tag provided (removed manual increment, SQL triggers handle it) (#35) ## [0.3.0] - 2025-12-15 ### Changed - Changed default download mode from `proxy` to `presigned` for better performance (#48) ### Added - Added presigned URL support for direct S3 downloads (#48) - Added `ORCHARD_DOWNLOAD_MODE` config option (`presigned`, `redirect`, `proxy`) (#48) - Added `ORCHARD_PRESIGNED_URL_EXPIRY` config option (default: 3600 seconds) (#48) - Added `?mode=` query parameter to override download mode per-request (#48) - Added `/api/v1/project/{project}/{package}/+/{ref}/url` endpoint for getting presigned URLs (#48) - Added `PresignedUrlResponse` schema with URL, expiry, checksums, and artifact metadata (#48) - Added MinIO ingress support in Helm chart for presigned URL access (#48) - Added `orchard.download.mode` and `orchard.download.presignedUrlExpiry` Helm values (#48) - Added integrity verification workflow design document (#24) - Added `sha256` field to API responses for clarity (alias of `id`) (#25) - Added `checksum_sha1` field to artifacts table for compatibility (#25) - Added `s3_etag` field to artifacts table for S3 verification (#25) - Compute and store MD5, SHA1, and S3 ETag alongside SHA256 during upload (#25) - Added `Dockerfile.local` and `docker-compose.local.yml` for local development (#25) - Added migration script `003_checksum_fields.sql` for existing databases (#25) ## [0.2.0] - 2025-12-15 ### Added - Added `format` and `platform` fields to packages table (#16) - Added `checksum_md5` and `metadata` JSONB fields to artifacts table (#16) - Added `updated_at` field to tags table (#16) - Added `tag_name`, `user_agent`, `duration_ms`, `deduplicated`, `checksum_verified` fields to uploads table (#16) - Added `change_type` field to tag_history table (#16) - Added composite indexes for common query patterns (#16) - Added GIN indexes on JSONB fields for efficient JSON queries (#16) - Added partial index for public projects (#16) - Added database triggers for `updated_at` timestamps (#16) - Added database triggers for maintaining artifact `ref_count` accuracy (#16) - Added CHECK constraints for data integrity (`size > 0`, `ref_count >= 0`) (#16) - Added migration script `002_schema_enhancements.sql` for existing databases (#16) ### Changed - Updated images to use internal container BSF proxy (#46) ## [0.1.0] - 2025-12-12 ### Added - Added Prosper docker template config (#45) ### Changed - Changed the Dockerfile npm build arg to use the deps.global.bsf.tools URL as the default registry (#45)