Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1,587 changes: 1,023 additions & 564 deletions .pnp.cjs

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,6 @@ packageExtensions:
'@monstrs/nestjs-dataloader@*':
dependencies:
'@nestjs/core': '*'
'@monstrs/nestjs-signed-url@*':
dependencies:
'@google-cloud/storage': '*'
'@nestjs/common@8':
dependencies:
'@types/node': '*'
Expand Down
4 changes: 2 additions & 2 deletions files/application/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
"type": "module",
"main": "src/index.ts",
"dependencies": {
"@atls/nestjs-gcs-client": "0.1.2",
"@atls/nestjs-signed-url": "0.6.4",
"@files/domain": "workspace:0.0.2",
"@files/persistence": "workspace:0.0.2",
"@monstrs/nestjs-signed-url": "0.1.3",
"@nestjs/common": "11.1.27",
"@nestjs/typeorm": "11.0.2",
"class-validator": "0.15.1",
Expand All @@ -16,7 +17,6 @@
},
"devDependencies": {
"@atls/nestjs-map-errors-interceptor": "^0.1.36",
"@google-cloud/storage": "4.3.1",
"@nestjs/core": "11.1.27",
"@nestjs/microservices": "11.1.27",
"@nestjs/testing": "11.1.27",
Expand Down
17 changes: 15 additions & 2 deletions files/application/src/module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import { SignedUrlModule } from '@monstrs/nestjs-signed-url'
import { GcsClientFactory } from '@atls/nestjs-gcs-client'
import { GcsClientModule } from '@atls/nestjs-gcs-client'
import { SignedUrlModule } from '@atls/nestjs-signed-url'
import { Module } from '@nestjs/common'

import { FileQueriesService } from './services/index.js'
import { UploadService } from './services/index.js'

@Module({
imports: [SignedUrlModule.gcs()],
imports: [
SignedUrlModule.gcsAsync<[GcsClientFactory]>({
imports: [
GcsClientModule.register({
apiEndpoint: process.env.GCS_API_ENDPOINT,
keyFilename: process.env.GCS_KEY_FILENAME,
}),
],
inject: [GcsClientFactory],
useFactory: (factory: GcsClientFactory) => factory.create(),
}),
],
providers: [FileQueriesService, UploadService],
exports: [FileQueriesService, UploadService],
})
Expand Down
14 changes: 9 additions & 5 deletions files/application/src/services/UploadService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SignedUrlService } from '@monstrs/nestjs-signed-url'
import { SignedUrlSigner } from '@atls/nestjs-signed-url'
import { Injectable } from '@nestjs/common'
import { extname } from 'path'
import { format } from 'path'
Expand All @@ -15,7 +15,7 @@ export class UploadService {
constructor(
private readonly uploadRepository: UploadEntityRepository,
private readonly fileRepository: FileEntityRepository,
private readonly signedUrlService: SignedUrlService
private readonly signedUrlSigner: SignedUrlSigner
) {}

async create(command: CreateUploadCommand): Promise<any> {
Expand All @@ -24,9 +24,13 @@ export class UploadService {
ext: extname(command.name),
})

const { url, fields } = await this.signedUrlService.generateWriteUrl(filename, {
type: command.type,
})
const { url, fields } = await this.signedUrlSigner.generateWriteUrl(
Comment thread
TorinAsakura marked this conversation as resolved.
process.env.GCS_BUCKET,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the local bucket fallback

When the files service runs under the checked-in docker-compose local stack, GCS_BUCKET=${GCS_BUCKET} is empty unless the developer exports it, while the only default bucket still provided there is FILES_BUCKET=dev. This new call now passes that empty process.env.GCS_BUCKET directly to the signer, so the default local upload flow reaches GCS signing with no bucket name and fails before clients can upload; either preserve the existing bucket fallback or update the compose/env defaults alongside this switch.

Useful? React with 👍 / 👎.

filename,
{
contentType: command.type,
}
)

const upload = Upload.create(command.id, command.type, command.name, url, fields)

Expand Down
2 changes: 1 addition & 1 deletion public-gateway/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"dependencies": {
"@apollo/server": "4.13.0",
"@atls/nestjs-dataloader": "0.0.14",
"@atls/nestjs-oathkeeper": "0.1.1",
"@grpc/grpc-js": "^1.5.3",
"@grpc/proto-loader": "0.5.5",
"@monstrs/oathkeeper-auth": "0.1.0",
"@nestjs/apollo": "13.2.1",
"@nestjs/common": "11.1.27",
"@nestjs/core": "11.1.27",
Expand Down
25 changes: 14 additions & 11 deletions public-gateway/app/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { oathkeeperAuth } from '@monstrs/oathkeeper-auth'
import { OathkeeperIdentityMiddleware } from '@atls/nestjs-oathkeeper'
import { NestFactory } from '@nestjs/core'

import { NestFactory } from '@nestjs/core'

import { ActivityMiddleware } from './middleware/index.js'
import { ApplicationModule } from './module.js'
import { ActivityMiddleware } from './middleware/index.js'
import { ApplicationModule } from './module.js'

declare const module: any

Expand Down Expand Up @@ -71,16 +70,20 @@ const resolveUserFromKratos = async (req: any, _res: any, next: () => void) => {
next()
}

const useOptionalOathkeeperAuth = (middleware: OathkeeperIdentityMiddleware) =>
async (req: any, res: any, next: () => void) => {
try {
await middleware.use(req, res, next)
} catch (error) {
next()
}
}

const bootstrap = async () => {
const app = await NestFactory.create(ApplicationModule)

if (process.env.NODE_ENV !== 'production') {
app.use(
oathkeeperAuth(
process.env.OATHKEEPER_DECISIONS_URL || 'http://serenity-oathkeeper-api:4456/decisions',
{ host: 'serenity.aunited.dev' }
)
)
app.use(useOptionalOathkeeperAuth(app.get(OathkeeperIdentityMiddleware)))
}

app.use(resolveUserFromKratos)
Expand Down
23 changes: 20 additions & 3 deletions public-gateway/app/src/module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Module } from '@nestjs/common'
import { join } from 'path'

import { DataLoaderInterceptor } from '@atls/nestjs-dataloader'
import { OathkeeperModule } from '@atls/nestjs-oathkeeper'
import { ApolloDriver } from '@nestjs/apollo'
import { ApolloDriverConfig } from '@nestjs/apollo'
import { Module } from '@nestjs/common'
import { APP_INTERCEPTOR } from '@nestjs/core'
import { GraphQLModule } from '@nestjs/graphql'
import { join } from 'path'

import { CatalogModule } from '@public-gateway/catalog'
import { CollaborationModule } from '@public-gateway/collaboration'
import { FilesModule } from '@public-gateway/files'
Expand All @@ -15,6 +16,11 @@ import { SearchModule } from '@public-gateway/search'

import { ActivityMiddleware } from './middleware/index.js'

const oathkeeperApiUrl =
process.env.OATHKEEPER_API_URL ||
process.env.OATHKEEPER_DECISIONS_URL?.replace(/\/decisions\/?$/, '') ||
'http://serenity-oathkeeper-api:4456'

// eslint-disable-next-line
const playground =
process.env.NODE_ENV !== 'production' || Boolean(process.env.PLAYGROUND)
Expand All @@ -27,6 +33,17 @@ const playground =

@Module({
imports: [
OathkeeperModule.register({
urls: {
api: oathkeeperApiUrl,
},
decision: {
forwardedHost: 'serenity.aunited.dev',
},
middleware: {
mode: 'enrich',
},
}),
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
introspection: true,
Expand Down
1 change: 0 additions & 1 deletion search/service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"@collaboration/domain": "0.0.1",
"@elastic/elasticsearch": "7.5.0",
"@godaddy/terminus": "4.3.1",
"@monstrs/nestjs-elasticsearch-indicator": "0.1.1",
"@nestjs/common": "11.1.27",
"@nestjs/core": "11.1.27",
"@nestjs/elasticsearch": "11.1.0",
Expand Down
8 changes: 6 additions & 2 deletions site/entrypoints/renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"@apollo/link-error": "^2.0.0-beta.3",
"@atls/nestjs-oathkeeper": "0.1.1",
"@atls/next-app-with-apollo": "^0.2.67",
"@atls/next-config-with-extract-intl-messages": "^0.0.1",
"@atls/next-config-with-pnp-workspaces": "^0.0.1",
Expand All @@ -19,15 +20,18 @@
"@emotion/server": "^11.4.0",
"@emotion/styled": "^11.3.0",
"@formatjs/intl-relativetimeformat": "4.4.3",
"@monstrs/oathkeeper-auth": "0.1.0",
"@nestjs/common": "11.1.27",
"@nestjs/core": "11.1.27",
"@site/specialists-detail-page": "0.0.1",
"events": "^3.3.0",
"express": "^4.17.1",
"graphql": "^16.3.0",
"next": "16.2.9",
"next-compose-plugins": "^2.2.0",
"next-fonts": "0.19.0",
"next-images": "1.2.0"
"next-images": "1.2.0",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.2"
},
"devDependencies": {
"@apollo/client": "3.5.8",
Expand Down
85 changes: 74 additions & 11 deletions site/entrypoints/renderer/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,80 @@
import { oathkeeperAuth } from '@monstrs/oathkeeper-auth'
import express from 'express'
import next from 'next'
import path from 'path'
import type { OathkeeperHeaders } from '@atls/nestjs-oathkeeper'
import type { OathkeeperModuleOptions } from '@atls/nestjs-oathkeeper'
import type { Request } from 'express'
import type { Response } from 'express'

import { OathkeeperDecisionService } from '@atls/nestjs-oathkeeper'
import express from 'express'
import next from 'next'
import path from 'path'

const oathkeeperApiUrl =
process.env.OATHKEEPER_API_URL ||
process.env.OATHKEEPER_DECISIONS_URL?.replace(/\/decisions\/?$/, '') ||
'http://serenity-oathkeeper-api:4456'

const createOathkeeperDecisionClient = (apiUrl: string) => ({
async decide(headers: OathkeeperHeaders) {
const response = await fetch(new URL('/decisions', apiUrl).toString(), {
headers,
method: 'GET',
})

return {
headers: response.headers,
status: response.status,
}
},
})

const createOathkeeperAuth = (forwardedHost: string) => {
const options: OathkeeperModuleOptions = {
decision: {
forwardedHost,
},
middleware: {
mode: 'enrich',
},
urls: {
api: oathkeeperApiUrl,
},
}

const decisions = new OathkeeperDecisionService(
createOathkeeperDecisionClient(oathkeeperApiUrl),
options
)

return async (req: Request, _res: Response, next: () => void) => {
try {
const decision = await decisions.decide({
headers: req.headers,
host: forwardedHost,
method: req.method || 'GET',
proto: req.protocol,
uri: req.url || '/',
})

if (decision.allowed) {
if (decision.authorization) {
req.headers.authorization = decision.authorization
}

if (decision.user) {
req.headers['x-user'] = decision.user
}
}
} catch (error) {}

next()
}
}

const bootstrap = async () => {
const app = next({
dev: process.env.NODE_ENV !== 'production',
dir: process.env.NODE_ENV !== 'production' ? path.join(__dirname, '../src/index.js') : __dirname,
dir:
process.env.NODE_ENV !== 'production' ? path.join(__dirname, '../src/index.js') : __dirname,
})

const handle = app.getRequestHandler()
Expand All @@ -16,12 +84,7 @@ const bootstrap = async () => {
const server = express()

if (process.env.NODE_ENV !== 'production') {
server.use(
oathkeeperAuth(
process.env.OATHKEEPER_DECISIONS_URL || 'http://serenity-oathkeeper-api:4456/decisions',
{ host: 'serenity.atls.tech' }
)
)
server.use(createOathkeeperAuth('serenity.atls.tech'))
}

server.get('*', (req, res) => handle(req, res))
Expand Down
Loading
Loading