Fix manifest push 500: use explicit SELECT instead of LastInsertId
SQLite's last_insert_rowid() only updates on actual INSERTs, not ON CONFLICT DO UPDATE. When pushing a second tag for an existing manifest digest, the upsert fires the conflict branch (no new row), so LastInsertId() returns a stale ID from a previous insert. This caused manifest_blobs and tags to reference the wrong manifest, producing a 500 on the PUT manifest response. Replace LastInsertId() with a SELECT id WHERE repository_id AND digest query within the same transaction. Security: manifest_blobs and tag foreign keys now always reference the correct manifest. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,8 +92,8 @@ func (d *DB) PushManifest(p PushManifestParams) error {
|
||||
}
|
||||
|
||||
// Step b: insert or update manifest.
|
||||
// Use INSERT OR REPLACE on the UNIQUE(repository_id, digest) constraint.
|
||||
result, err := tx.Exec(
|
||||
// Use INSERT ... ON CONFLICT DO UPDATE on the UNIQUE(repository_id, digest) constraint.
|
||||
_, err = tx.Exec(
|
||||
`INSERT INTO manifests (repository_id, digest, media_type, content, size)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT(repository_id, digest) DO UPDATE SET
|
||||
@@ -106,10 +106,22 @@ func (d *DB) PushManifest(p PushManifestParams) error {
|
||||
_ = tx.Rollback()
|
||||
return fmt.Errorf("db: insert manifest: %w", err)
|
||||
}
|
||||
manifestID, err := result.LastInsertId()
|
||||
|
||||
// Retrieve the manifest ID by querying the row directly. We cannot use
|
||||
// result.LastInsertId() here because SQLite's last_insert_rowid() is
|
||||
// unreliable after an ON CONFLICT DO UPDATE — it returns the rowid of
|
||||
// the most recent *insert* in the connection, not the upserted row.
|
||||
// When the conflict branch fires (no new row inserted), the stale
|
||||
// last_insert_rowid from a previous insert is returned, causing
|
||||
// manifest_blobs and tags to reference the wrong manifest.
|
||||
var manifestID int64
|
||||
err = tx.QueryRow(
|
||||
`SELECT id FROM manifests WHERE repository_id = ? AND digest = ?`,
|
||||
repoID, p.Digest,
|
||||
).Scan(&manifestID)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return fmt.Errorf("db: manifest last insert id: %w", err)
|
||||
return fmt.Errorf("db: get manifest id after upsert: %w", err)
|
||||
}
|
||||
|
||||
// Step c: populate manifest_blobs join table.
|
||||
|
||||
Reference in New Issue
Block a user