diff --git a/config/custom-environment-variables.yml b/config/custom-environment-variables.yml index 3afe51a5450b5..2b3081f2ae2d8 100644 --- a/config/custom-environment-variables.yml +++ b/config/custom-environment-variables.yml @@ -93,7 +93,6 @@ private: obs_pass: 'OBS_PASS' redis_url: 'REDIS_URL' sentry_dsn: 'SENTRY_DSN' - shields_secret: 'SHIELDS_SECRET' sl_insight_userUuid: 'SL_INSIGHT_USER_UUID' sl_insight_apiToken: 'SL_INSIGHT_API_TOKEN' sonarqube_token: 'SONARQUBE_TOKEN' diff --git a/core/server/secret-is-valid.js b/core/server/secret-is-valid.js deleted file mode 100644 index c8b87ffda123f..0000000000000 --- a/core/server/secret-is-valid.js +++ /dev/null @@ -1,18 +0,0 @@ -function constEq(a, b) { - if (a.length !== b.length) { - return false - } - let zero = 0 - for (let i = 0; i < a.length; i++) { - zero |= a.charCodeAt(i) ^ b.charCodeAt(i) - } - return zero === 0 -} - -function makeSecretIsValid(shieldsSecret) { - return function secretIsValid(secret = '') { - return shieldsSecret && constEq(secret, shieldsSecret) - } -} - -export { makeSecretIsValid } diff --git a/core/server/server.js b/core/server/server.js index 8b5b166b35719..7a2b1d814a3a1 100644 --- a/core/server/server.js +++ b/core/server/server.js @@ -177,7 +177,6 @@ const privateConfigSchema = Joi.object({ obs_pass: Joi.string(), redis_url: Joi.string().uri({ scheme: ['redis', 'rediss'] }), sentry_dsn: Joi.string(), - shields_secret: Joi.string(), sl_insight_userUuid: Joi.string(), sl_insight_apiToken: Joi.string(), sonarqube_token: Joi.string(), diff --git a/core/token-pooling/token-pool.js b/core/token-pooling/token-pool.js index 7dcf64ad5abdf..34010ed53664f 100644 --- a/core/token-pooling/token-pool.js +++ b/core/token-pooling/token-pool.js @@ -328,29 +328,6 @@ class TokenPool { this.fifoQueue.forEach(visit) this.priorityQueue.forEach(visit) } - - allValidTokenIds() { - const result = [] - this.forEach(({ id }) => result.push(id)) - return result - } - - serializeDebugInfo({ sanitize = true } = {}) { - const maybeSanitize = sanitize ? id => sanitizeToken(id) : id => id - - const priorityQueue = [] - this.priorityQueue.forEach(t => - priorityQueue.push(t.getDebugInfo({ sanitize })) - ) - - return { - utcEpochSeconds: getUtcEpochSeconds(), - allValidTokenIds: this.allValidTokenIds().map(maybeSanitize), - fifoQueue: this.fifoQueue.map(t => t.getDebugInfo({ sanitize })), - priorityQueue, - sanitized: sanitize, - } - } } export { sanitizeToken, Token, TokenPool } diff --git a/core/token-pooling/token-pool.spec.js b/core/token-pooling/token-pool.spec.js index fdfa937d200a1..373a4ef479ff8 100644 --- a/core/token-pooling/token-pool.spec.js +++ b/core/token-pooling/token-pool.spec.js @@ -19,10 +19,6 @@ describe('The token pool', function () { ids.forEach(id => tokenPool.add(id)) }) - it('allValidTokenIds() should return the full list', function () { - expect(tokenPool.allValidTokenIds()).to.deep.equal(ids) - }) - it('should yield the expected tokens', function () { ids.forEach(id => times(batchSize, () => expect(tokenPool.next().id).to.equal(id)) @@ -38,67 +34,6 @@ describe('The token pool', function () { ) }) - describe('serializeDebugInfo should initially return the expected', function () { - beforeEach(function () { - sinon.useFakeTimers({ now: 1544307744484 }) - }) - - afterEach(function () { - sinon.restore() - }) - - context('sanitize is not specified', function () { - it('returns fully sanitized results', function () { - // This is `sha()` of '1', '2', '3', '4', '5'. These are written - // literally for avoidance of doubt as to whether sanitization is - // happening. - const sanitizedIds = [ - '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b', - 'd4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35', - '4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce', - '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a', - 'ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d', - ] - - expect(tokenPool.serializeDebugInfo()).to.deep.equal({ - allValidTokenIds: sanitizedIds, - priorityQueue: [], - fifoQueue: sanitizedIds.map(id => ({ - data: '[redacted]', - id, - isFrozen: false, - isValid: true, - nextReset: Token.nextResetNever, - usesRemaining: batchSize, - })), - sanitized: true, - utcEpochSeconds: 1544307744, - }) - }) - }) - - context('with sanitize: false', function () { - it('returns unsanitized results', function () { - expect(tokenPool.serializeDebugInfo({ sanitize: false })).to.deep.equal( - { - allValidTokenIds: ids, - priorityQueue: [], - fifoQueue: ids.map(id => ({ - data: undefined, - id, - isFrozen: false, - isValid: true, - nextReset: Token.nextResetNever, - usesRemaining: batchSize, - })), - sanitized: false, - utcEpochSeconds: 1544307744, - } - ) - }) - }) - }) - context('tokens are marked exhausted immediately', function () { it('should be exhausted', function () { ids.forEach(() => { diff --git a/scripts/github_token_backup.fish b/scripts/github_token_backup.fish deleted file mode 100755 index 8aef250809784..0000000000000 --- a/scripts/github_token_backup.fish +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env fish -# -# Back up the GitHub tokens from each production server. -# - -if test (count $argv) -lt 1 - echo Usage: (basename (status -f)) shields_secret -end - -set shields_secret $argv[1] - -function do_backup - set server $argv[1] - curl --insecure -u ":$shields_secret" "https://$server.servers.shields.io/\$github-auth/tokens" > "$server""_tokens.json" -end - -for server in s0 s1 s2 - do_backup $server -end diff --git a/services/github/auth/admin.js b/services/github/auth/admin.js deleted file mode 100644 index 9ffea4d056415..0000000000000 --- a/services/github/auth/admin.js +++ /dev/null @@ -1,32 +0,0 @@ -import { makeSecretIsValid } from '../../../core/server/secret-is-valid.js' - -function setRoutes({ shieldsSecret }, { apiProvider, server }) { - const secretIsValid = makeSecretIsValid(shieldsSecret) - - // Allow the admin to obtain the tokens for operational and debugging - // purposes. This could be used to: - // - // - Ensure tokens have been propagated to all servers - // - Debug GitHub badge failures - // - // The admin can authenticate with HTTP Basic Auth, with an empty/any - // username and the shields secret in the password and an empty/any - // password. - // - // e.g. - // curl --insecure -u ':very-very-secret' 'https://img.shields.io/$github-auth/tokens' - server.ajax.on('github-auth/tokens', (json, end, ask) => { - if (!secretIsValid(ask.password)) { - // An unknown entity tries to connect. Let the connection linger for a minute. - return setTimeout(() => { - ask.res.statusCode = 401 - ask.res.setHeader('Cache-Control', 'private') - end('Invalid secret.') - }, 10000) - } - ask.res.setHeader('Cache-Control', 'private') - end(apiProvider.serializeDebugInfo({ sanitize: false })) - }) -} - -export { setRoutes } diff --git a/services/github/auth/admin.spec.js b/services/github/auth/admin.spec.js deleted file mode 100644 index fb751498e0270..0000000000000 --- a/services/github/auth/admin.spec.js +++ /dev/null @@ -1,71 +0,0 @@ -import { expect } from 'chai' -import Camp from '@shields_io/camp' -import portfinder from 'portfinder' -import got from '../../../core/got-test-client.js' -import GithubApiProvider from '../github-api-provider.js' -import { setRoutes } from './admin.js' - -describe('GitHub admin route', function () { - const shieldsSecret = '7'.repeat(40) - - let port, baseUrl - before(async function () { - port = await portfinder.getPortPromise() - baseUrl = `http://127.0.0.1:${port}` - }) - - let camp - before(async function () { - camp = Camp.start({ port, hostname: '::' }) - await new Promise(resolve => camp.on('listening', () => resolve())) - }) - after(async function () { - if (camp) { - await new Promise(resolve => camp.close(resolve)) - camp = undefined - } - }) - - before(function () { - const apiProvider = new GithubApiProvider({ withPooling: true }) - setRoutes({ shieldsSecret }, { apiProvider, server: camp }) - }) - - context('the password is correct', function () { - it('returns a valid JSON response', async function () { - const { statusCode, body, headers } = await got( - `${baseUrl}/$github-auth/tokens`, - { - username: '', - password: shieldsSecret, - responseType: 'json', - } - ) - expect(statusCode).to.equal(200) - expect(body).to.be.ok - expect(headers['cache-control']).to.equal('private') - }) - }) - - // Disabled because this code isn't modified often and the test is very - // slow. To run it, run `SLOW=true npm run test:core` - // - // I wasn't able to make this work with fake timers: - // https://github.com/sinonjs/sinon/issues/1739 - if (process.env.SLOW) { - context('the password is missing', function () { - it('returns the expected message', async function () { - this.timeout(11000) - const { statusCode, body, headers } = await got( - `${baseUrl}/$github-auth/tokens`, - { - throwHttpErrors: false, - } - ) - expect(statusCode).to.equal(401) - expect(body).to.equal('"Invalid secret."') - expect(headers['cache-control']).to.equal('private') - }) - }) - } -}) diff --git a/services/github/github-api-provider.js b/services/github/github-api-provider.js index bfb26c20abf77..59647fd7bb1fd 100644 --- a/services/github/github-api-provider.js +++ b/services/github/github-api-provider.js @@ -54,18 +54,6 @@ class GithubApiProvider { } } - serializeDebugInfo({ sanitize = true } = {}) { - if (this.withPooling) { - return { - standardTokens: this.standardTokens.serializeDebugInfo({ sanitize }), - searchTokens: this.searchTokens.serializeDebugInfo({ sanitize }), - graphqlTokens: this.graphqlTokens.serializeDebugInfo({ sanitize }), - } - } else { - return {} - } - } - addToken(tokenString) { if (this.withPooling) { this.standardTokens.add(tokenString) diff --git a/services/github/github-constellation.js b/services/github/github-constellation.js index e74114e7a46f9..429f8a9fde9b4 100644 --- a/services/github/github-constellation.js +++ b/services/github/github-constellation.js @@ -2,7 +2,6 @@ import { AuthHelper } from '../../core/base-service/auth-helper.js' import RedisTokenPersistence from '../../core/token-pooling/redis-token-persistence.js' import log from '../../core/server/log.js' import GithubApiProvider from './github-api-provider.js' -import { setRoutes as setAdminRoutes } from './auth/admin.js' import { setRoutes as setAcceptorRoutes } from './auth/acceptor.js' // Convenience class with all the stuff related to the Github API and its @@ -23,7 +22,6 @@ class GithubConstellation { constructor(config) { this._debugEnabled = config.service.debug.enabled this._debugIntervalSeconds = config.service.debug.intervalSeconds - this.shieldsSecret = config.private.shields_secret const { redis_url: redisUrl, gh_token: globalToken } = config.private if (redisUrl) { @@ -74,9 +72,6 @@ class GithubConstellation { this.apiProvider.addToken(tokenString) }) - const { shieldsSecret, apiProvider } = this - setAdminRoutes({ shieldsSecret }, { apiProvider, server }) - if (this.oauthHelper.isConfigured) { setAcceptorRoutes({ server,