Skip to content
Open
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
18 changes: 9 additions & 9 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"lodash-es": "^4.18.1",
"mjml": "5.3.0",
"mongodb": "^7.2.0",
"mongoose": "9.2.2",
"mongoose": "9.4.1",
"morgan": "^1.10.1",
"nanoid": "^5.1.11",
"node-cache": "^5.1.2",
Expand Down
8 changes: 4 additions & 4 deletions backend/src/connectors/audit/stroom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,23 +258,23 @@ export class StroomAuditConnector extends BaseAuditConnector {
}

async onCreateRelease(req: Request, release: ReleaseDoc) {
this.auditGenericEvent(req, `${release.modelId}:${release.semver}`)
this.auditGenericEvent(req, `${release.modelId}:${release.semverString}`)
}

async onViewRelease(req: Request, release: ReleaseDoc) {
this.auditGenericEvent(req, `${release.modelId}:${release.semver}`)
this.auditGenericEvent(req, `${release.modelId}:${release.semverString}`)
}

async onViewReleases(req: Request, releases: ReleaseDoc[]) {
this.auditMultipleViewEvent(
req,
releases.map((release) => ({ Id: `${release.modelId}:${release.semver}` })),
releases.map((release) => ({ Id: `${release.modelId}:${release.semverString}` })),
'release',
)
}

async onUpdateRelease(req: Request, release: ReleaseDoc) {
this.auditGenericEvent(req, `${release.modelId}:${release.semver}`)
this.auditGenericEvent(req, `${release.modelId}:${release.semverString}`)
}

async onDeleteRelease(req: Request, modelId: string, semver: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export async function up() {
const deletedReviews: ReviewDoc[] = []

// For each deleted release, deleted the reviews associated with it
for (const { modelId, semver } of deletedReleases) {
const reviews = await removeReleaseReviews(modelId, semver)
for (const { modelId, semverString } of deletedReleases) {
const reviews = await removeReleaseReviews(modelId, semverString)
deletedReviews.push(...reviews)
}

Expand Down
4 changes: 2 additions & 2 deletions backend/src/migrations/025_fix_partial_020_2426.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export async function up() {
const deletedReviews: ReviewDoc[] = []

// For each deleted release, find the already deleted reviews (from 020_2426_remove_orphaned_reviews_responses.ts) associated with it
for (const { modelId, semver } of deletedReleases) {
for (const { modelId, semverString } of deletedReleases) {
const reviews: ReviewDoc[] = await Review.find({
modelId,
semver,
semver: semverString,
deleted: true,
})
deletedReviews.push(...reviews)
Expand Down
4 changes: 2 additions & 2 deletions backend/src/models/File.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HydratedDocument, model, ObjectId, Schema } from 'mongoose'
import { HydratedDocument, model, Schema, Types } from 'mongoose'

import { SoftDeleteDocument, SoftDeleteInterface, softDeletionPlugin } from './plugins/softDeletePlugin.js'
import { ScanInterface } from './Scan.js'
Expand All @@ -7,7 +7,7 @@ import { ScanInterface } from './Scan.js'
// It should be used for plain object representations, e.g. for sending to the
// client.
export interface FileInterface {
_id: ObjectId
_id: Types.ObjectId
modelId: string

name: string
Expand Down
39 changes: 25 additions & 14 deletions backend/src/models/Release.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { HydratedDocument, model, ObjectId, Schema, Types } from 'mongoose'

import { semverObjectToString, semverStringToObject } from '../services/release.js'
import { semverObjectToString, semverStringToObject } from '../utils/semver.js'
import { SoftDeleteDocument, softDeletionPlugin } from './plugins/softDeletePlugin.js'

// This interface stores information about the properties on the base object.
Expand All @@ -10,7 +10,7 @@ export interface ReleaseInterface {
modelId: string
modelCardVersion: number

semver: string
semver: SemverObject
notes: string

minor: boolean
Expand All @@ -26,6 +26,10 @@ export interface ReleaseInterface {
updatedAt: Date
}

export interface ReleaseVirtuals {
semverString: string
}

export interface ImageNameRef {
repository: string
name: string
Expand All @@ -44,7 +48,12 @@ export type ImageRef = ImageTagRef | ImageDigestRef
export type ReleaseDoc = HydratedDocument<
Omit<ReleaseInterface, 'images'> & {
images: Array<HydratedDocument<ImageTagRef>>
}
},
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
{},
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
{},
ReleaseVirtuals
> &
SoftDeleteDocument

Expand All @@ -55,24 +64,15 @@ export interface SemverObject {
metadata?: string
}

const ReleaseSchema = new Schema<ReleaseDoc & { semver: string | SemverObject }>(
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
const ReleaseSchema = new Schema<ReleaseDoc, {}, {}, ReleaseVirtuals>(
{
modelId: { type: String, required: true },
modelCardVersion: { type: Number, required: true },

semver: {
type: Schema.Types.Mixed,
required: true,
set: function (semver: string) {
return semverStringToObject(semver)
},
get: function (semver: SemverObject | string) {
if (typeof semver === 'string') {
return semver
} else {
return semverObjectToString(semver)
}
},
},

notes: { type: String, required: true },
Expand Down Expand Up @@ -110,6 +110,17 @@ const ReleaseSchema = new Schema<ReleaseDoc & { semver: string | SemverObject }>
},
)

ReleaseSchema.virtual('semverString').get(function () {
return semverObjectToString(this.semver)
})
ReleaseSchema.virtual('semverString').set(function (semver: SemverObject | string) {
if (typeof semver === 'string') {
this.semver = semverStringToObject(semver)
} else {
this.semver = semver
}
})

ReleaseSchema.plugin(softDeletionPlugin)
ReleaseSchema.index({ modelId: 1, semver: 1 }, { unique: true })
ReleaseSchema.index({ modelId: 1 })
Expand Down
6 changes: 3 additions & 3 deletions backend/src/models/Response.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HydratedDocument, model, ObjectId, Schema } from 'mongoose'
import { HydratedDocument, model, Schema, Types } from 'mongoose'

import { SoftDeleteDocument, softDeletionPlugin } from './plugins/softDeletePlugin.js'

Expand All @@ -16,13 +16,13 @@ export const ResponseKind = {
export type ResponseKindKeys = (typeof ResponseKind)[keyof typeof ResponseKind]

export interface ResponseInterface {
_id: ObjectId
_id: Types.ObjectId
entity: string
kind: ResponseKindKeys
role?: string
decision?: DecisionKeys
comment?: string
parentId: Schema.Types.ObjectId
parentId: Types.ObjectId
reactions: ResponseReaction[]
commentEditedAt?: string

Expand Down
4 changes: 2 additions & 2 deletions backend/src/models/Review.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HydratedDocument, model, ObjectId, Schema } from 'mongoose'
import { HydratedDocument, model, Schema, Types } from 'mongoose'

import { ReviewKind } from '../types/enums.js'
import { SoftDeleteDocument, softDeletionPlugin } from './plugins/softDeletePlugin.js'
Expand All @@ -24,7 +24,7 @@ export type ReviewInterface =
} & PartialReviewInterface)

type PartialReviewInterface = {
_id: ObjectId
_id: Types.ObjectId
modelId: string
role: string
createdAt: string
Expand Down
4 changes: 2 additions & 2 deletions backend/src/models/Scan.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { HydratedDocument, model, type ObjectId, Schema } from 'mongoose'
import { HydratedDocument, model, Schema, Types } from 'mongoose'

import type { ModelScanResponse, TrivyScanResultResponse } from '../clients/artefactScan.js'
import { ArtefactScanState, type ArtefactScanStateKeys } from '../connectors/artefactScanning/Base.js'
import { type SoftDeleteDocument, softDeletionPlugin } from './plugins/softDeletePlugin.js'

export type ScanInterface = {
_id: ObjectId
_id: Types.ObjectId

toolName: string
scannerVersion?: string
Expand Down
4 changes: 2 additions & 2 deletions backend/src/models/Token.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import bcrypt from 'bcryptjs'
import { createHash } from 'crypto'
import { HydratedDocument, model, ObjectId, Schema } from 'mongoose'
import { HydratedDocument, model, Schema, Types } from 'mongoose'

import { BadReq } from '../utils/error.js'
import { SoftDeleteDocument, softDeletionPlugin } from './plugins/softDeletePlugin.js'
Expand Down Expand Up @@ -66,7 +66,7 @@ export type HashTypeKeys = (typeof HashType)[keyof typeof HashType]
// It should be used for plain object representations, e.g. for sending to the
// client.
export interface TokenInterface {
_id: ObjectId
_id: Types.ObjectId

user: string
description: string
Expand Down
4 changes: 2 additions & 2 deletions backend/src/routes/v2/release/getRelease.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ registerPath({
})

interface getReleaseResponse {
release: ReleaseInterface & { files: FileWithScanResultsAggregate[] }
release: Omit<ReleaseInterface, 'semver'> & { semver: string; files: FileWithScanResultsAggregate[] }
}

export const getRelease = [
Expand All @@ -52,7 +52,7 @@ export const getRelease = [
const release = await getReleaseBySemver(req.user, modelId, semver)
await audit.onViewRelease(req, release)
const files = await getFilesByIds(req.user, modelId, release.fileIds)
const releaseWithFiles = { ...release.toObject(), files, kind: ResponseKind.Comment }
const releaseWithFiles = { ...release.toObject(), semver: release.semverString, files, kind: ResponseKind.Comment }

res.json({
release: releaseWithFiles,
Expand Down
6 changes: 5 additions & 1 deletion backend/src/seeds/data/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ export const release: ReleaseInterface = {
modelId: 'example',
modelCardVersion: 0,

semver: 'v1.0.0',
semver: {
major: 1,
minor: 0,
patch: 0,
},
notes: `This makes major steps forward in both speed and quality of \
results given by the model. Here is a table of the updated speed:

Expand Down
6 changes: 2 additions & 4 deletions backend/src/services/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ export async function uploadFile(
}

export async function saveImportedFile(file: FileInterface) {
await FileModel.findOneAndUpdate({ modelId: file.modelId, _id: file._id }, file, {
upsert: true,
})
await FileModel.findOneAndUpdate({ modelId: file.modelId, _id: file._id }, file, { upsert: true })
}

export async function startUploadMultipartFile(
Expand Down Expand Up @@ -363,7 +361,7 @@ export async function removeFiles(

// Unless specified, we don't actually remove the file from storage, we only hide all
// references to it. This makes the file not visible to the user.
await FileModel.findOneAndDelete({ _id: file._id }, session)
await FileModel.findByIdAndDelete(file._id, session)
// We cannot use the mongo session with aws-sdk so send the aws-sdk API call last as if
// aws-sdk fails then the mongo session will roll back
if (hardDelete) {
Expand Down
5 changes: 3 additions & 2 deletions backend/src/services/mirroredModel/exporters/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { UserInterface } from '../../../models/User.js'
import { MirrorExportLogData, MirrorKind } from '../../../types/types.js'
import config from '../../../utils/config.js'
import { BadReq, InternalError } from '../../../utils/error.js'
import { semverObjectToString } from '../../../utils/semver.js'
import { getFilesByIds, getTotalFileSize } from '../../file.js'
import log from '../../log.js'
import { getModelCardRevisions } from '../../model.js'
Expand Down Expand Up @@ -40,7 +41,7 @@ export class DocumentsExporter extends BaseExporter {

protected async _init() {
if (this.releases.length > 0) {
const semvers = this.getSemvers()
const semvers = this.getSemvers().map((semver) => semverObjectToString(semver))
const fileIds = await getAllFileIds(this.model.id, semvers)
this.files = await getFilesByIds(this.user, this.model.id, fileIds)

Expand Down Expand Up @@ -201,7 +202,7 @@ export class DocumentsExporter extends BaseExporter {
error,
modelId: this.model.id,
mirroredModelId: this.model!.settings.mirror.destinationModelId!,
releaseId: release.id,
releaseId: release._id.toString(),
...this.logData,
})
}
Expand Down
10 changes: 5 additions & 5 deletions backend/src/services/mirroredModel/importers/documents.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PassThrough } from 'node:stream'
import { json } from 'node:stream/consumers'

import { ObjectId } from 'mongoose'
import { Types } from 'mongoose'
import { Headers } from 'tar-stream'

import { ReleaseAction } from '../../../connectors/authorisation/actions.js'
Expand All @@ -28,9 +28,9 @@ export type MongoDocumentMirrorInformation = {
metadata: DocumentsMirrorMetadata
modelCardVersions: ModelCardRevisionDoc['version'][]
newModelCards: Omit<ModelCardRevisionDoc, '_id'>[]
releaseSemvers: ReleaseDoc['semver'][]
releaseSemvers: ReleaseDoc['semverString'][]
newReleases: Omit<ReleaseDoc, '_id'>[]
fileIds: { key: ObjectId; name: string }[]
fileIds: { key: Types.ObjectId; name: string }[]
imageIds: string[]
}

Expand All @@ -41,7 +41,7 @@ export class DocumentsImporter extends BaseImporter {

protected modelCardVersions: number[] = []
protected releaseSemvers: string[] = []
protected fileIds: { key: ObjectId; name: string }[] = []
protected fileIds: { key: Types.ObjectId; name: string }[] = []
protected imageIds: string[] = []
protected newModelCards: Omit<ModelCardRevisionDoc, '_id'>[] = []
protected newReleases: Omit<ReleaseDoc, '_id'>[] = []
Expand Down Expand Up @@ -118,7 +118,7 @@ export class DocumentsImporter extends BaseImporter {
} as DistributionPackageName),
)
}
this.releaseSemvers.push(release.semver)
this.releaseSemvers.push(release.semverString)
const savedRelease = await saveImportedRelease(release)
if (savedRelease) {
this.newReleases.push(savedRelease)
Expand Down
Loading
Loading