fix: change last used date encoding (#7925)

This commit is contained in:
Laurin 2026-03-27 14:34:14 +01:00 committed by GitHub
parent 883e0bcb02
commit 12c990c2d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 71 additions and 13 deletions

View file

@ -74,7 +74,7 @@ import { UpdateSchemaPolicyForOrganization, UpdateSchemaPolicyForProject } from
import { collect, CollectedOperation, legacyCollect } from './usage';
import { generateUnique, getServiceHost, pollForEmailVerificationLink } from './utils';
function createConnectionPool() {
function getPGConnectionString() {
const pg = {
user: ensureEnv('POSTGRES_USER'),
password: ensureEnv('POSTGRES_PASSWORD'),
@ -83,8 +83,12 @@ function createConnectionPool() {
db: ensureEnv('POSTGRES_DB'),
};
return `postgres://${pg.user}:${pg.password}@${pg.host}:${pg.port}/${pg.db}?sslmode=disable`;
}
function createConnectionPool() {
return createPostgresDatabasePool({
connectionParameters: `postgres://${pg.user}:${pg.password}@${pg.host}:${pg.port}/${pg.db}?sslmode=disable`,
connectionParameters: getPGConnectionString(),
});
}
@ -141,6 +145,7 @@ export function initSeed() {
return {
pollForEmailVerificationLink,
getPGConnectionString,
async purgeOIDCDomains() {
const pool = await getPool();
await pool.query(psql`

View file

@ -1,5 +1,7 @@
import { pollFor, readTokenInfo } from 'testkit/flow';
import { ProjectType } from 'testkit/gql/graphql';
import { createTokenStorage } from '@hive/storage';
import { generateToken } from '@hive/tokens';
import { initSeed } from '../../testkit/seed';
test.concurrent('deleting a token should clear the cache', async () => {
@ -144,3 +146,59 @@ test.concurrent(
`);
},
);
test.concurrent(
'regression: reading existing token with "last_used_at" from pg database (and not redis cache) does not raise an exception',
async ({ expect }) => {
const seed = initSeed();
const { createOrg } = await seed.createOwner();
const { createProject, organization } = await createOrg();
const { project, target } = await createProject();
const tokenStorage = await createTokenStorage(seed.getPGConnectionString(), 1);
try {
const token = generateToken();
// create new token so it does not yet exist in redis cache
const record = await tokenStorage.createToken({
name: 'foo',
organization: organization.id,
project: project.id,
target: target.id,
scopes: [],
token: token.hash,
tokenAlias: token.alias,
});
// touch the token so it has a date
await tokenStorage.touchTokens({ tokens: [{ token: record.token, date: new Date() }] });
const result = await readTokenInfo(token.secret).then(res => res.expectNoGraphQLErrors());
expect(result.tokenInfo).toMatchInlineSnapshot(`
{
__typename: TokenInfo,
hasOrganizationDelete: false,
hasOrganizationIntegrations: false,
hasOrganizationMembers: false,
hasOrganizationRead: false,
hasOrganizationSettings: false,
hasProjectAlerts: false,
hasProjectDelete: false,
hasProjectOperationsStoreRead: false,
hasProjectOperationsStoreWrite: false,
hasProjectRead: false,
hasProjectSettings: false,
hasTargetDelete: false,
hasTargetRead: false,
hasTargetRegistryRead: false,
hasTargetRegistryWrite: false,
hasTargetSettings: false,
hasTargetTokensRead: false,
hasTargetTokensWrite: false,
}
`);
} finally {
await tokenStorage.destroy();
}
},
);

View file

@ -21,7 +21,7 @@ const tokenFields = psql`
, "token_alias" AS "tokenAlias"
, "name"
, to_json("created_at") AS "date"
, "last_used_at" AS "lastUsedAt"
, to_json("last_used_at") AS "lastUsedAt"
, "organization_id" AS "organization"
, "project_id" AS "project"
, "target_id" AS "target"
@ -75,7 +75,7 @@ export async function createTokenStorage(
LIMIT 1
`,
)
.then(TokenModel.parse);
.then(TokenModel.nullable().parse);
},
async createToken({
token,

View file

@ -3,6 +3,9 @@
"type": "module",
"license": "MIT",
"private": true,
"exports": {
".": "./src/api.ts"
},
"scripts": {
"build": "tsx ../../../scripts/runify.ts",
"dev": "tsup-node --config ../../../configs/tsup/dev.config.node.ts src/dev.ts",

View file

@ -24,7 +24,7 @@ function hashToken(token: string) {
return createHash('sha256').update(token).digest('hex');
}
function generateToken() {
export function generateToken() {
const token = createHash('md5')
.update(String(Math.random()))
.update(String(Date.now()))

View file

@ -13266,10 +13266,6 @@ packages:
resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==}
engines: {node: '>=18'}
globalthis@1.0.3:
resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
engines: {node: '>= 0.4'}
globalthis@1.0.4:
resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}
engines: {node: '>= 0.4'}
@ -34813,10 +34809,6 @@ snapshots:
globals@16.5.0: {}
globalthis@1.0.3:
dependencies:
define-properties: 1.2.1
globalthis@1.0.4:
dependencies:
define-properties: 1.2.1