Commit graph registry/internal/database/migrations/008_separate_official_metadata.sql
Author SHA1 Message Date
Tadas Antanavicius
e968cfdbca
fix: renumber migrations to fix staging deployment (#592)
## Summary

Fixes staging deployment by renumbering migrations to match what staging
has already applied.

## Problem

Staging already applied migration 008 (metadata separation) before we
inserted the new cleanup migration. When we added the cleanup as 008 and
renumbered metadata to 009, staging tried to apply 009 again and failed
with "column already exists".

## Current State

- **Staging**: Has run original 008 (metadata separation), marked as
complete. Failed trying to run 009 (which is the same migration
renumbered).
- **Production**: Has not run either 008 or 009 yet.

## Solution

- Rename `008_clean_invalid_data.sql` → `007a_clean_invalid_data.sql`
- Rename `009_separate_official_metadata.sql` →
`008_separate_official_metadata.sql` (back to original)

## How This Fixes It

With this renumbering:

1. **Staging behavior**:
- Sees 008 is already complete (the metadata migration it already ran)
- Sees 007a as new and runs it, but it will be a no-op (skips because
staging doesn't have the problematic production data)
   - Continues normally

2. **Production behavior**:
   - Runs 007a (cleanup migration) - removes invalid data
- Runs 008 (metadata separation) - applies successfully because data is
now clean
   - Both migrations run in the correct order as intended

## Testing

- Verified migration order works correctly
- Tested on empty database (test environment) - 007a skips as expected
- Tested with production data snapshot - 007a cleans data, 008 applies
successfully

This is a critical fix to unblock staging deployment.
2025-09-30 20:39:33 +03:00
Tadas Antanavicius
272ee9322d
fix: add server name validation and clean invalid data before migration 009 (#591)
## Summary

This PR adds two important improvements to ensure data integrity:

1. **Adds server name format validation at the API layer** to match the
database constraint from migration 008
2. **Includes migration 008 to clean up invalid data** before applying
strict constraints in migration 009

## Changes

### Server Name Validation
- Enforces validation at the API layer matching the database constraint
- **Namespace pattern**: `[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]` 
  - Must start and end with alphanumeric characters
  - Can contain dots and hyphens in the middle
- **Name pattern**: `[a-zA-Z0-9][a-zA-Z0-9._-]*[a-zA-Z0-9]`
  - Must start and end with alphanumeric characters  
  - Can contain dots, underscores, and hyphens in the middle
- Provides clear, user-friendly error messages indicating which part is
invalid
- Uses DRY approach with composed regex patterns

### Migration 008: Data Cleanup
- Removes servers with invalid names or empty versions (5 servers
affected in production)
- Fixes invalid status values by setting them to 'active' (1 server
affected)
- Removes duplicate name+version combinations
- Includes comprehensive safety checks to prevent accidental data loss
- Must run before migration 009 which adds strict constraints

## Testing
- All validator tests pass
- Migration includes safety checks that match production data
- CI verification included

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-30 20:07:42 +03:00
Tadas Antanavicius
2d49e5b68c
fix: prevent NULL status values during migration 008 (#587)
## Summary
- Fixes migration 008 failing with "column contains null values" error
- Adds COALESCE protection to handle 126 servers without status fields
- Includes test utilities to reproduce and verify fixes with production
data

## Problem

Migration 008 was failing in production because:
- 126 out of 781 servers have no `status` field in their JSON
- When extracting `rec.value->>'status'`, these became NULL values
- The `ALTER TABLE servers ALTER COLUMN status SET NOT NULL` constraint
then failed

## Solution

1. **Prevent NULLs during migration**: Use COALESCE to provide 'active'
default when status is NULL/empty
2. **Enhanced debugging**: Added RAISE NOTICE statements to log
problematic values
3. **Safety check**: Double-check that throws exception if any NULLs
remain
4. **Test utilities**: Created mirror_data tools to test migrations with
real production data

## Testing

Created and used `scripts/mirror_data/` tools to:
- Fetch all 781 servers from production API
- Load them into a test database
- Verify the migration fix works correctly

### Results:
- **Before fix**: 126 NULL status values created during migration
- **After fix**: 0 NULL status values, all servers have valid status
- Migration completes successfully with NOT NULL constraint

## Test plan
- [x] Tested locally with production data using mirror_data tools
- [x] Verified 0 NULL values after migration (vs 126 before)
- [x] Confirmed NOT NULL constraint adds successfully
- [ ] Deploy to staging and verify migration succeeds
- [ ] Monitor production deployment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-30 06:43:26 -07:00
Radoslav Dimitrov
e39b008b41
Ensure we populate sane defaults for NULL values (#583)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR tries to ensure sane defaults for entries that for one
reason or another have NULL values for some of their properties.

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-09-30 15:47:18 +03:00
Tadas Antanavicius
3dc4f93370
fix: handle NULL status values in migration 008 (#578)
## Problem

Production deployment is failing with CrashLoopBackOff. Migration 008
fails with:
```
ERROR: column "status" of relation "servers" contains null values (SQLSTATE 23502)
```

## Root Cause

The migration extracts the `status` field from an unexpected location in
the data structure.

### Actual Data Structure (Before Migration)

In the current format, `status` is at the **top level** of the JSON, not
nested in official metadata:

```json
{
  "name": "com.example/server",
  "version": "1.0.0",
  "status": "active",           ← STATUS IS HERE (top level)
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "serverId": "uuid",
      "publishedAt": "2025-09-01T00:00:00Z",
      "isLatest": true
      // NO STATUS FIELD HERE
    }
  }
}
```

For 120 out of 765 servers, the status field is **missing entirely**:
```json
{
  "name": "com.biodnd/agent-ip",
  "version": "0.1.2",
  // ← NO STATUS FIELD AT ALL
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "serverId": "uuid",
      "publishedAt": "2025-09-23T09:47:07Z",
      "isLatest": true
      // STILL NO STATUS FIELD HERE
    }
  }
}
```

### Original Migration Logic

```sql
IF official_meta IS NOT NULL THEN
    UPDATE servers
    SET
        status = (official_meta->>'status'),  -- Extracts NULL for all servers
```

**Result:** 
- All 765 servers would have NULL status extracted
- Because `official_meta->>'status'` returns NULL (field doesn't exist
there)
- The migration tries to add `NOT NULL` constraint → fails

### Fixed Migration Logic

```sql
IF official_meta IS NOT NULL THEN
    UPDATE servers
    SET
        status = COALESCE(NULLIF(rec.value->>'status', 'null'), 'active'),
```

**Result:**
- Extracts from top-level JSON where status actually exists
- `NULLIF(rec.value->>'status', 'null')` handles edge case of literal
string "null"
- `COALESCE(..., 'active')` provides fallback when status is missing
- All servers get valid status value

### Impact Breakdown

**645 servers with `"status": "active"`:**
- Before fix: Would extract NULL → migration fails
- After fix: Extracts "active" correctly

**120 servers with missing status field:**
- Before fix: Would extract NULL → migration fails  
- After fix: Defaults to 'active' via COALESCE

## Example Servers with Missing Status

(First 9 discovered during investigation)
- com.biodnd/agent-ip
- io.github.jkakar/cookwith-mcp
- com.joelverhagen.mcp/Knapcode.SampleMcpServer
- io.github.Lyellr88/marm-mcp-server
- com.biodnd/agent-press
- io.github.timheuer/sampledotnetmcpserver
- io.github.CodeCraftersLLC/local-voice-mcp
- com.biodnd/agent-fin
- io.github.ruvnet/ruv-swarm

## Testing

Verified against production data (765 total servers):
- ✅ All servers have official metadata
- ✅ None have status in official metadata (expected)
- ✅ 645 have "status": "active" at top level
- ✅ 120 have missing status field (no field present)
- ✅ Fix extracts from correct location for all cases

## Impact

This unblocks production deployment. Once merged and released as v1.2.1,
the migration will:
1. Extract status from the correct location (top-level JSON)
2. Handle missing status fields with sensible defaults
3. Successfully add NOT NULL constraint
4. Allow pods to start normally

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-09-30 10:21:48 +03:00
Radoslav Dimitrov
b21c6f564d
Changes on the server.json format and the API (#562) 2025-09-29 23:30:35 +03:00