Fix CI: lint, formatting, test, CodeQL, and generated types ordering

- Sort CSS properties alphabetically in StyledPublishMethodLabel
- Fix prettier formatting in app-register.ts and server test/service files
- Update test assertion for twenty-app- prefix normalization
- Remove unused ApplicationExceptionCode import in test
- Use replaceAll instead of replace for URL encoding (CodeQL)
- Correct alphabetical ordering in generated GraphQL types

Made-with: Cursor
This commit is contained in:
Félix Malfait
2026-03-07 11:12:11 +01:00
parent d4ce4414e2
commit 8d6ec2a92b
7 changed files with 29 additions and 58 deletions
@@ -99,7 +99,7 @@ describe('copyBaseApplicationProject', () => {
expect(await fs.pathExists(packageJsonPath)).toBe(true);
const packageJson = await fs.readJson(packageJsonPath);
expect(packageJson.name).toBe('my-test-app');
expect(packageJson.name).toBe('twenty-app-my-test-app');
expect(packageJson.version).toBe('0.1.0');
expect(packageJson.devDependencies['twenty-sdk']).toBe(
createTwentyAppPackageJson.version,
@@ -2458,6 +2458,7 @@ export type Mutation = {
initiateOTPProvisioningForAuthenticatedUser: InitiateTwoFactorAuthenticationProvisioning;
installApplication: Scalars['Boolean'];
installMarketplaceApp: Scalars['Boolean'];
registerNpmPackage: ApplicationRegistration;
removeQueryFromEventStream: Scalars['Boolean'];
removeRoleFromAgent: Scalars['Boolean'];
renewApplicationToken: ApplicationTokenPair;
@@ -2537,7 +2538,6 @@ export type Mutation = {
verifyEmailAndGetLoginToken: VerifyEmailAndGetLoginToken;
verifyEmailAndGetWorkspaceAgnosticToken: AvailableWorkspacesAndAccessTokens;
verifyEmailingDomain: EmailingDomain;
registerNpmPackage: ApplicationRegistration;
verifyTwoFactorAuthenticationMethodForAuthenticatedUser: VerifyTwoFactorAuthenticationMethod;
};
@@ -3058,6 +3058,11 @@ export type MutationInstallMarketplaceAppArgs = {
};
export type MutationRegisterNpmPackageArgs = {
packageName: Scalars['String'];
};
export type MutationRemoveQueryFromEventStreamArgs = {
input: RemoveQueryFromEventStreamInput;
};
@@ -3481,11 +3486,6 @@ export type MutationVerifyEmailingDomainArgs = {
};
export type MutationRegisterNpmPackageArgs = {
packageName: Scalars['String'];
};
export type MutationVerifyTwoFactorAuthenticationMethodForAuthenticatedUserArgs = {
otp: Scalars['String'];
};
@@ -28,8 +28,8 @@ const StyledButtonContainer = styled.div`
`;
const StyledPublishMethodLabel = styled.div`
font-size: ${themeCssVariables.font.size.sm};
color: ${themeCssVariables.font.color.light};
font-size: ${themeCssVariables.font.size.sm};
margin-bottom: ${themeCssVariables.spacing[2]};
margin-top: ${themeCssVariables.spacing[4]};
`;
@@ -31,20 +31,14 @@ export class AppRegisterCommand {
console.log(chalk.green('Package registered successfully!'));
console.log(chalk.gray(` Name: ${result.data.name}`));
console.log(
chalk.gray(` ID: ${result.data.universalIdentifier}`),
);
console.log(chalk.gray(` ID: ${result.data.universalIdentifier}`));
if (result.data.isProvenanceVerified) {
console.log(
chalk.green(' Provenance: Verified'),
);
console.log(chalk.green(' Provenance: Verified'));
if (result.data.provenanceRepositoryUrl) {
console.log(
chalk.gray(
` Repository: ${result.data.provenanceRepositoryUrl}`,
),
chalk.gray(` Repository: ${result.data.provenanceRepositoryUrl}`),
);
}
} else {
@@ -1,12 +1,11 @@
import {
ApplicationException,
ApplicationExceptionCode,
} from 'src/engine/core-modules/application/application.exception';
import { ApplicationException } from 'src/engine/core-modules/application/application.exception';
import { assertValidNpmPackageName } from 'src/engine/core-modules/application/application-package/utils/assert-valid-npm-package-name.util';
describe('assertValidNpmPackageName', () => {
it('should accept valid twenty-app- prefixed names', () => {
expect(() => assertValidNpmPackageName('twenty-app-my-cool-app')).not.toThrow();
expect(() =>
assertValidNpmPackageName('twenty-app-my-cool-app'),
).not.toThrow();
expect(() => assertValidNpmPackageName('twenty-app-hello')).not.toThrow();
});
@@ -23,9 +22,9 @@ describe('assertValidNpmPackageName', () => {
});
it('should reject scoped packages without twenty-app- prefix', () => {
expect(() =>
assertValidNpmPackageName('@myorg/my-cool-app'),
).toThrow(ApplicationException);
expect(() => assertValidNpmPackageName('@myorg/my-cool-app')).toThrow(
ApplicationException,
);
});
it('should reject invalid npm package names', () => {
@@ -10,9 +10,7 @@ import { ApplicationRegistrationService } from 'src/engine/core-modules/applicat
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { type UserEntity } from 'src/engine/core-modules/user/user.entity';
const createMockUser = (
overrides: Partial<UserEntity> = {},
): UserEntity =>
const createMockUser = (overrides: Partial<UserEntity> = {}): UserEntity =>
({
id: 'user-123',
email: '[email protected]',
@@ -59,9 +57,7 @@ describe('ApplicationNpmRegistrationService', () => {
}).compile();
service = module.get(ApplicationNpmRegistrationService);
applicationRegistrationService = module.get(
ApplicationRegistrationService,
);
applicationRegistrationService = module.get(ApplicationRegistrationService);
applicationPackageFetcherService = module.get(
ApplicationPackageFetcherService,
);
@@ -101,11 +97,7 @@ describe('ApplicationNpmRegistrationService', () => {
});
await expect(
service.registerNpmPackage(
'twenty-app-test',
user,
'workspace-1',
),
service.registerNpmPackage('twenty-app-test', user, 'workspace-1'),
).rejects.toThrow(ApplicationRegistrationException);
});
@@ -203,19 +195,14 @@ describe('ApplicationNpmRegistrationService', () => {
{} as any,
);
await service.registerNpmPackage(
'twenty-app-test',
user,
'workspace-1',
);
await service.registerNpmPackage('twenty-app-test', user, 'workspace-1');
expect(
applicationRegistrationService.upsertFromNpmRegistration,
).toHaveBeenCalledWith(
expect.objectContaining({
isProvenanceVerified: true,
provenanceRepositoryUrl:
'https://github.com/user/twenty-app-test',
provenanceRepositoryUrl: 'https://github.com/user/twenty-app-test',
provenanceVerifiedAt: expect.any(Date),
}),
);
@@ -17,10 +17,7 @@ type NpmPackument = {
name: string;
'dist-tags': Record<string, string>;
maintainers: Array<{ name: string; email: string }>;
versions: Record<
string,
{ dist?: { tarball?: string; integrity?: string } }
>;
versions: Record<string, { dist?: { tarball?: string; integrity?: string } }>;
};
export type ProvenanceMetadata = {
@@ -30,9 +27,7 @@ export type ProvenanceMetadata = {
@Injectable()
export class ApplicationNpmRegistrationService {
private readonly logger = new Logger(
ApplicationNpmRegistrationService.name,
);
private readonly logger = new Logger(ApplicationNpmRegistrationService.name);
constructor(
private readonly twentyConfigService: TwentyConfigService,
@@ -55,7 +50,7 @@ export class ApplicationNpmRegistrationService {
}
const { data } = await axios.get<NpmPackument>(
`${registryUrl}/${encodeURIComponent(packageName).replace('%40', '@')}`,
`${registryUrl}/${encodeURIComponent(packageName).replaceAll('%40', '@')}`,
{ headers, timeout: 15_000 },
);
@@ -142,10 +137,8 @@ export class ApplicationNpmRegistrationService {
ownerWorkspaceId: workspaceId,
createdByUserId: user.id,
latestAvailableVersion: latestVersion ?? null,
isProvenanceVerified:
provenanceMetadata?.hasProvenance ?? false,
provenanceRepositoryUrl:
provenanceMetadata?.repositoryUrl ?? null,
isProvenanceVerified: provenanceMetadata?.hasProvenance ?? false,
provenanceRepositoryUrl: provenanceMetadata?.repositoryUrl ?? null,
provenanceVerifiedAt: provenanceMetadata?.hasProvenance
? new Date()
: null,
@@ -176,9 +169,7 @@ export class ApplicationNpmRegistrationService {
}
for (const attestation of data.attestations) {
if (
attestation.predicateType !== 'https://slsa.dev/provenance/v1'
) {
if (attestation.predicateType !== 'https://slsa.dev/provenance/v1') {
continue;
}