Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic octokit instantiation based on auth status #1248

Merged
merged 7 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bldrs",
"version": "1.0.1080",
"version": "1.0.1084",
"main": "src/index.jsx",
"license": "AGPL-3.0",
"homepage": "https://github.com/bldrs-ai/Share",
Expand Down
6 changes: 6 additions & 0 deletions src/BaseRoutes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {navWith} from './utils/navigate'
import useStore from './store/useStore'
import * as Sentry from '@sentry/react'
import {useAuth0} from './Auth0/Auth0Proxy'
import {initializeOctoKit} from './net/github/OctokitExport'


const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes)
Expand Down Expand Up @@ -75,6 +76,11 @@ export default function BaseRoutes({testElt = null}) {
scope: 'openid profile email offline_access repo',
},
}).then((token) => {
if (token !== '') {
initializeOctoKit(true)
} else {
initializeOctoKit(false)
}
setAccessToken(token)
}).catch((err) => {
if (err.error !== 'login_required') {
Expand Down
84 changes: 58 additions & 26 deletions src/__mocks__/api-handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {MOCK_REPOSITORY, MOCK_USER_REPOSITORIES} from '../net/github/Repositorie
import testEnvVars from '../../tools/jest/testEnvVars'


const GH_BASE = testEnvVars.GITHUB_BASE_URL
const GH_BASE_AUTHED = testEnvVars.GITHUB_BASE_URL
const GH_BASE_UNAUTHED = testEnvVars.GITHUB_BASE_URL_UNAUTHENTICATED

const httpOk = 200
const httpCreated = 201
Expand All @@ -25,7 +26,8 @@ const httpNotFound = 404
export function initHandlers() {
const handlers = []
handlers.push(...gaHandlers())
handlers.push(...githubHandlers())
handlers.push(...githubHandlers(null, true))
handlers.push(...githubHandlers(null, false))
return handlers
}

Expand Down Expand Up @@ -53,9 +55,9 @@ function gaHandlers() {
* @param {object} githubStore todo implementation
* @return {Array<object>} handlers
*/
function githubHandlers(githubStore) {
function githubHandlers(githubStore, authed) {
return [
rest.get(`${GH_BASE}/repos/:org/:repo/issues`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues`, (req, res, ctx) => {
const {org, repo} = req.params
const createdIssues = createMockIssues(org, repo, sampleIssues)
return res(
Expand All @@ -64,7 +66,7 @@ function githubHandlers(githubStore) {
)
}),

rest.get(`${GH_BASE}/repos/:org/:repo/issues/:issueNumber/comments`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues/:issueNumber/comments`, (req, res, ctx) => {
const {org, repo, issueNumber} = req.params

if (org !== 'pablo-mayrgundter' || repo !== 'Share' || !issueNumber) {
Expand All @@ -76,7 +78,7 @@ function githubHandlers(githubStore) {
)
}),

rest.get(`${GH_BASE}/repos/:org/:repo/contents/:path`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/contents/:path`, (req, res, ctx) => {
const {org, repo, path} = req.params
const ref = req.url.searchParams.get('ref')

Expand Down Expand Up @@ -142,9 +144,9 @@ function githubHandlers(githubStore) {
path: 'README.md',
sha: 'a5dd511780350dfbf2374196d8f069114a7d9205',
size: 1359,
url: `${GH_BASE}/repos/bldrs-ai/Share/contents/README.md?ref=main`,
url: `${GH_BASE_UNAUTHED}/repos/bldrs-ai/Share/contents/README.md?ref=main`,
html_url: 'https://github.com/bldrs-ai/Share/blob/main/README.md',
git_url: `${GH_BASE}/repos/bldrs-ai/Share/git/blobs/a5dd511780350dfbf2374196d8f069114a7d9205`,
git_url: `${GH_BASE_UNAUTHED}/repos/bldrs-ai/Share/git/blobs/a5dd511780350dfbf2374196d8f069114a7d9205`,
download_url: downloadURL,
type: 'file',
content: 'U2hhcmUgaXMgYSB3ZWItYmFzZWQgQklNICYgQ0FEIGludGVncmF0aW9uIGVu\n' +
Expand Down Expand Up @@ -180,15 +182,15 @@ function githubHandlers(githubStore) {
'Oi1HdWlkZSkK\n',
encoding: 'base64',
links: {
self: `${GH_BASE}/repos/bldrs-ai/Share/contents/README.md?ref=main`,
git: `${GH_BASE}/repos/bldrs-ai/Share/git/blobs/a5dd511780350dfbf2374196d8f069114a7d9205`,
self: `${GH_BASE_UNAUTHED}/repos/bldrs-ai/Share/contents/README.md?ref=main`,
git: `${GH_BASE_UNAUTHED}/repos/bldrs-ai/Share/git/blobs/a5dd511780350dfbf2374196d8f069114a7d9205`,
html: 'https://github.com/bldrs-ai/Share/blob/main/README.md',
},
}),
)
}),

rest.post(`${GH_BASE}/repos/:org/:repo/issues`, (req, res, ctx) => {
rest.post(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues`, (req, res, ctx) => {
const {org, repo} = req.params

if ( !(org === 'bldrs-ai' || org === 'pablo-mayrgundter') || repo !== 'Share') {
Expand All @@ -205,7 +207,7 @@ function githubHandlers(githubStore) {
)
}),

rest.post(`${GH_BASE}/repos/:org/:repo/issues/:issueNumber/comments`, (req, res, ctx) => {
rest.post(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues/:issueNumber/comments`, (req, res, ctx) => {
const {org, repo, issueNumber} = req.params

if (org !== 'pablo-mayrgundter' || repo !== 'Share' || !issueNumber) {
Expand All @@ -216,7 +218,7 @@ function githubHandlers(githubStore) {
)
}),

rest.patch(`${GH_BASE}/repos/:org/:repo/issues/:issueNumber`, (req, res, ctx) => {
rest.patch(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues/:issueNumber`, (req, res, ctx) => {
const {org, repo} = req.params
if (org !== 'pablo-mayrgundter' || repo !== 'Share' ) {
return res(
Expand All @@ -232,7 +234,7 @@ function githubHandlers(githubStore) {
)
}),

rest.delete(`${GH_BASE}/repos/:org/:repo/issues/comments/:commentId`, (req, res, ctx) => {
rest.delete(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:org/:repo/issues/comments/:commentId`, (req, res, ctx) => {
const {org, repo, commentId} = req.params

if (org !== 'bldrs-ai' || repo !== 'Share' || !commentId) {
Expand All @@ -244,7 +246,7 @@ function githubHandlers(githubStore) {
)
}),

rest.get(`${GH_BASE}/user/orgs`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/user/orgs`, (req, res, ctx) => {
const authHeader = req.headers.get('authorization')

if (!authHeader) {
Expand All @@ -263,14 +265,14 @@ function githubHandlers(githubStore) {
)
}),

rest.get(`${GH_BASE}/user/repos`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/user/repos`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json(MOCK_USER_REPOSITORIES.data),
)
}),

rest.get(`${GH_BASE}/orgs/bldrs-ai/repos`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/orgs/bldrs-ai/repos`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json({
Expand All @@ -279,22 +281,22 @@ function githubHandlers(githubStore) {
)
}),

rest.get(`${GH_BASE}/repos/:owner/:repo/contents`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/contents`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json(MOCK_FILES),
)
}),

rest.get(`${GH_BASE}/repos/:owner/:repo/branches`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/branches`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json(MOCK_BRANCHES),
)
}),


rest.get(`${GH_BASE}/repos/:owner/:repo/commits`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/commits`, (req, res, ctx) => {
// Directly check req.params for 'failurecaseowner' and 'failurecaserepo'
if (req.params.owner === 'failurecaseowner' && req.params.repo === 'failurecaserepo') {
return res(
Expand All @@ -307,7 +309,37 @@ function githubHandlers(githubStore) {
ctx.status(httpOk),
ctx.json([]),
)
// Handle unauthenticated case
} else if (req.params.owner === 'unauthedcaseowner' && req.params.repo === 'unauthedcaserepo' ) {
const requestUrl = req.url.toString()

if ( requestUrl.includes(GH_BASE_AUTHED)) {
return res(
ctx.status(httpNotFound),
ctx.json({sha: 'error'}),
)
} else {
return res(
ctx.status(httpOk),
ctx.json(MOCK_COMMITS),
)
}
// Handle authenticated case
} else if (req.params.owner === 'authedcaseowner' && req.params.repo === 'authedcaserepo' ) {
const requestUrl = req.url.toString()

if ( requestUrl.includes(GH_BASE_UNAUTHED)) {
return res(
ctx.status(httpNotFound),
ctx.json({sha: 'error'}),
)
} else {
return res(
ctx.status(httpOk),
ctx.json(MOCK_COMMITS),
)
}
}
// For all other cases, return a success response
return res(
ctx.status(httpOk),
Expand All @@ -321,23 +353,23 @@ function githubHandlers(githubStore) {
* GH returns for the various cases. */

// octokit.rest.git.getRef
rest.get(`${GH_BASE}/repos/:owner/:repo/git/ref/:ref`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/ref/:ref`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json({object: {sha: 'parentSha'}}),
)
}),

// octokit.rest.git.getCommit
rest.get(`${GH_BASE}/repos/:owner/:repo/git/commits/:commit_sha`, (req, res, ctx) => {
rest.get(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/commits/:commit_sha`, (req, res, ctx) => {
return res(
ctx.status(httpOk),
ctx.json({tree: {sha: 'treeSha'}}),
)
}),

// octokit.rest.git.createBlob
rest.post(`${GH_BASE}/repos/:owner/:repo/git/blobs`, async (req, res, ctx) => {
rest.post(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/blobs`, async (req, res, ctx) => {
const {content, encoding} = await req.body
if (content === undefined || encoding === undefined) {
const HTTP_BAD_REQUEST = 400
Expand All @@ -350,7 +382,7 @@ function githubHandlers(githubStore) {
}),

// octokit.rest.git.createTree
rest.post(`${GH_BASE}/repos/:owner/:repo/git/trees`, async (req, res, ctx) => {
rest.post(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/trees`, async (req, res, ctx) => {
// eslint-disable-next-line camelcase
const {base_tree, tree} = await req.body
// eslint-disable-next-line camelcase
Expand All @@ -365,7 +397,7 @@ function githubHandlers(githubStore) {
}),

// octokit.rest.git.createCommit
rest.post(`${GH_BASE}/repos/:owner/:repo/git/commits`, async (req, res, ctx) => {
rest.post(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/commits`, async (req, res, ctx) => {
const {message, tree, parents} = await req.body
if (message === undefined || tree === undefined || parents === undefined) {
const HTTP_BAD_REQUEST = 400
Expand All @@ -378,7 +410,7 @@ function githubHandlers(githubStore) {
}),

// octokit.rest.git.updateRef
rest.patch(`${GH_BASE}/repos/:owner/:repo/git/refs/:ref`, async (req, res, ctx) => {
rest.patch(`${authed ? GH_BASE_AUTHED : GH_BASE_UNAUTHED}/repos/:owner/:repo/git/refs/:ref`, async (req, res, ctx) => {
const {sha} = await req.body
if (sha === undefined) {
const HTTP_BAD_REQUEST = 400
Expand Down
2 changes: 1 addition & 1 deletion src/net/github/Branches.fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL_UNAUTHENTICATED


export const MOCK_BRANCHES = {
Expand Down
2 changes: 1 addition & 1 deletion src/net/github/Comments.fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL_UNAUTHENTICATED


export const MOCK_COMMENTS = {
Expand Down
2 changes: 1 addition & 1 deletion src/net/github/Commits.fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL_UNAUTHENTICATED


export const MOCK_COMMITS = [{
Expand Down
30 changes: 30 additions & 0 deletions src/net/github/Commits.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import {
getLatestCommitHash,
} from './Commits'

import {initializeOctoKit} from './OctokitExport'


describe('net/github/Commits', () => {
beforeEach(() => {
initializeOctoKit(false) // Default to unauthenticated initialization
})

it('get latest commit hash', async () => {
const result = await getLatestCommitHash('testowner', 'testrepo', '', '', '')
expect(result).toEqual('testsha1testsha1testsha1testsha1testsha1')
Expand All @@ -17,4 +23,28 @@ describe('net/github/Commits', () => {
.toThrow('Unknown error: {"sha":"error"}')
})
})

describe('Unauthenticated initialization', () => {
it('should NOT throw an error on getLatestCommitHash with unauthedcaseowner and unauthedcaserepo', async () => {
const result = await getLatestCommitHash('unauthedcaseowner', 'unauthedcaserepo', '', '', '')
expect(result).toEqual('testsha1testsha1testsha1testsha1testsha1')
})
})

describe('Authenticated initialization', () => {
beforeEach(() => {
// Authenticated initialization for this test
initializeOctoKit(true)
})

it('should NOT throw an error on getLatestCommitHash with authedcaseowner and authedcaserepo', async () => {
const result = await getLatestCommitHash('authedcaseowner', 'authedcaserepo', '', '', '')
expect(result).toEqual('testsha1testsha1testsha1testsha1testsha1')
})

afterEach(() => {
// Reset to unauthenticated for subsequent tests
initializeOctoKit(false)
})
})
})
2 changes: 1 addition & 1 deletion src/net/github/Files.fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL_UNAUTHENTICATED
const RAW_GIT_PROXY_URL = process.env.RAW_GIT_PROXY_URL


Expand Down
3 changes: 2 additions & 1 deletion src/net/github/Files.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {assertDefined} from '../../utils/assert'
import {getGitHub, octokit} from './Http' // TODO(pablo): don't use octokit directly
import {octokit} from './OctokitExport'
import {getGitHub} from './Http' // TODO(pablo): don't use octokit directly
import {checkCache, updateCache} from './Cache'


Expand Down
18 changes: 1 addition & 17 deletions src/net/github/Http.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import {Octokit} from '@octokit/rest'
import {assertDefined} from '../../utils/assert'
import PkgJson from '../../../package.json'
import {checkCache, updateCache} from './Cache'

import {octokit} from './OctokitExport'

/**
* Fetch the resource at the given path from GitHub, substituting in the given args
Expand Down Expand Up @@ -155,17 +153,3 @@ function requestWithTimeout(octokitRequest, timeout = 10000) { // Default timeou
),
])
}


const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
// All direct uses of octokit should be private to this file to
// ensure we setup mocks for local use and unit testing.
export const octokit = new Octokit({
baseUrl: GITHUB_BASE_URL,
userAgent: `bldrs/${PkgJson.version}`,
// This comment instructs GitHub to always use the latest response instead of using a cached version. Especially relevant for notee.
// https://github.com/octokit/octokit.js/issues/890#issuecomment-392193948 the source of the solution
headers: {
'If-None-Match': '',
},
})
2 changes: 1 addition & 1 deletion src/net/github/Issues.fixture.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL
const GITHUB_BASE_URL = process.env.GITHUB_BASE_URL_UNAUTHENTICATED

export const sampleIssues = [
{
Expand Down
Loading