backdate_token_expiry.mjs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import minimist from 'minimist'
  2. import { db, ObjectId } from '../../app/src/infrastructure/mongodb.mjs'
  3. import { scriptRunner } from '../lib/ScriptRunner.mjs'
  4. // Test helper: move a personal access token's accessTokenExpiresAt EARLIER, to
  5. // simulate an expiring-soon or already-expired token when manually testing the
  6. // expiry-notification flow (notify_expiring_tokens.mjs / git-bridge messaging).
  7. //
  8. // This script can only ever back-date a token: it refuses to set an expiry that
  9. // is later than the token's current one. Moving an expiry forward would extend
  10. // the life of a token that should be dead, so that direction is disallowed.
  11. //
  12. // Pass --dry-run to report what would change without writing.
  13. async function main() {
  14. const opts = parseArgs()
  15. const token = await db.oauthAccessTokens.findOne({
  16. _id: new ObjectId(opts.tokenId),
  17. })
  18. if (token == null) {
  19. console.error(`No oauthAccessToken found with _id ${opts.tokenId}`)
  20. process.exit(1)
  21. }
  22. const currentExpiry = token.accessTokenExpiresAt
  23. if (!(currentExpiry instanceof Date) || isNaN(currentExpiry.getTime())) {
  24. console.error(
  25. `Token ${opts.tokenId} has no valid accessTokenExpiresAt ` +
  26. `(found: ${JSON.stringify(currentExpiry)}). ` +
  27. 'This script only operates on tokens with an expiry, such as PATs.'
  28. )
  29. process.exit(1)
  30. }
  31. if (opts.expiry >= currentExpiry) {
  32. console.error(
  33. `Refusing to move expiry forward: requested ${opts.expiry.toISOString()} ` +
  34. `is not earlier than current ${currentExpiry.toISOString()}. ` +
  35. 'This script only back-dates token expiry.'
  36. )
  37. process.exit(1)
  38. }
  39. if (opts.dryRun) {
  40. console.warn(
  41. `[dry run] would back-date token ${opts.tokenId} expiry from ` +
  42. `${currentExpiry.toISOString()} to ${opts.expiry.toISOString()}`
  43. )
  44. return
  45. }
  46. await db.oauthAccessTokens.updateOne(
  47. { _id: token._id },
  48. { $set: { accessTokenExpiresAt: opts.expiry } }
  49. )
  50. console.warn(
  51. `Back-dated token ${opts.tokenId} expiry from ` +
  52. `${currentExpiry.toISOString()} to ${opts.expiry.toISOString()}`
  53. )
  54. }
  55. function parseArgs() {
  56. const args = minimist(process.argv.slice(2), {
  57. boolean: ['help', 'dry-run'],
  58. })
  59. if (args.help) {
  60. usage()
  61. process.exit(0)
  62. }
  63. if (args._.length !== 0) {
  64. usage()
  65. process.exit(1)
  66. }
  67. const tokenId = args['token-id']
  68. if (tokenId == null) {
  69. console.error('Missing --token-id option')
  70. process.exit(1)
  71. }
  72. if (!ObjectId.isValid(tokenId)) {
  73. console.error(`Invalid --token-id: ${tokenId}`)
  74. process.exit(1)
  75. }
  76. if (args['expiry-date'] == null) {
  77. console.error('Missing --expiry-date option')
  78. process.exit(1)
  79. }
  80. const expiry = new Date(args['expiry-date'])
  81. if (isNaN(expiry.getTime())) {
  82. console.error(`Invalid --expiry-date: ${args['expiry-date']}`)
  83. process.exit(1)
  84. }
  85. return {
  86. tokenId,
  87. expiry,
  88. dryRun: args['dry-run'],
  89. }
  90. }
  91. function usage() {
  92. console.error(`Usage: backdate_token_expiry.mjs [OPTS...]
  93. Moves a personal access token's expiry EARLIER, to simulate an expiring or
  94. expired token when testing the expiry-notification flow. Only ever back-dates;
  95. refuses to move an expiry forward.
  96. Options:
  97. --token-id _id of the oauthAccessToken to back-date
  98. --expiry-date New expiry, earlier than the current one (e.g. 2026-06-01T00:00:00Z)
  99. --dry-run Report the change without writing
  100. --help Show this message
  101. `)
  102. }
  103. try {
  104. await scriptRunner(main)
  105. process.exit(0)
  106. } catch (error) {
  107. console.error(error)
  108. process.exit(1)
  109. }