Add migration to track invalid ABM token state (#48560)

**Related issue:** Resolves #47698

# Checklist for submitter

If some of the following don't apply, delete the relevant line.


## Testing

- [x] Added/updated automated tests

- [x] QA'd all new/changed functionality manually

## Database migrations

- [x] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [x] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added support for marking ABM tokens as invalid with a new
default-enabled status field.
* Existing token records are now initialized with a valid default state
during the update.

* **Tests**
* Added coverage to verify the new token status field is created
correctly and backfilled for existing records.


<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Andrew Mellor
2026-07-21 17:01:53 +01:00
committed by GitHub
parent b8f1897f06
commit d5d1b1197e
3 changed files with 65 additions and 2 deletions
@@ -0,0 +1,21 @@
package tables
import (
"database/sql"
"fmt"
)
func init() {
MigrationClient.AddMigration(Up_20260721090128, Down_20260721090128)
}
func Up_20260721090128(tx *sql.Tx) error {
if _, err := tx.Exec(`ALTER TABLE abm_tokens ADD COLUMN token_invalid TINYINT(1) NOT NULL DEFAULT '0'`); err != nil {
return fmt.Errorf("adding token_invalid column to abm_tokens table: %w", err)
}
return nil
}
func Down_20260721090128(tx *sql.Tx) error {
return nil
}
@@ -0,0 +1,41 @@
package tables
import (
"testing"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/stretchr/testify/require"
)
func TestUp_20260721090128(t *testing.T) {
db := applyUpToPrev(t)
// Insert a row before the migration to verify existing rows get the correct default.
enrollmentToken, err := fleet.GenerateRandom32ByteEntropyURLSafeToken()
require.NoError(t, err)
_, err = db.Exec(`INSERT INTO abm_tokens (organization_name, apple_id, renew_at, token, enrollment_url_token) VALUES ('test-org', 'test@apple.com', NOW(), 'token', ?)`, enrollmentToken)
require.NoError(t, err)
applyNext(t, db)
// Verify existing row was backfilled with default value of 0.
var tokenInvalid int
err = db.QueryRow(`SELECT token_invalid FROM abm_tokens WHERE organization_name = 'test-org'`).Scan(&tokenInvalid)
require.NoError(t, err)
require.Equal(t, 0, tokenInvalid)
// Verify column structure.
var colName, colType, isNullable, colDefault string
err = db.QueryRow(`
SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'abm_tokens'
AND COLUMN_NAME = 'token_invalid'
`).Scan(&colName, &colType, &isNullable, &colDefault)
require.NoError(t, err)
require.Equal(t, "token_invalid", colName)
require.Equal(t, "tinyint(1)", colType)
require.Equal(t, "NO", isNullable)
require.Equal(t, "0", colDefault)
}
File diff suppressed because one or more lines are too long