From 1bd25bfcff4b32c3a317a719ac24f85f87b263d7 Mon Sep 17 00:00:00 2001 From: Jakub Dzikowski Date: Fri, 3 Apr 2026 10:49:50 +0200 Subject: [PATCH 1/2] Feat: Disable org-level auth for BatchSubmit and delegate auth for operations in batch only Signed-off-by: Jakub Dzikowski --- chain-cli/README.md | 2 +- .../e2e/__snapshots__/api.spec.ts.snap | 6 +++--- .../src/apples/__snapshots__/api.spec.ts.snap | 2 +- .../src/pk/__snapshots__/api.spec.ts.snap | 2 +- .../src/token/__snapshots__/api.spec.ts.snap | 2 +- chaincode/src/contracts/GalaContract.ts | 4 +--- chaincode/src/contracts/GalaTransaction.ts | 7 +++++-- .../__snapshots__/PublicKeyContract.spec.ts.snap | 2 +- chaincode/src/contracts/authorize.ts | 14 +++++++++++++- 9 files changed, 27 insertions(+), 14 deletions(-) diff --git a/chain-cli/README.md b/chain-cli/README.md index 7cc0612715..a12c44e73b 100644 --- a/chain-cli/README.md +++ b/chain-cli/README.md @@ -20,7 +20,7 @@ $ npm install -g @gala-chain/cli $ galachain COMMAND running command... $ galachain (--version) -@gala-chain/cli/3.0.0 linux-x64 node-v24.13.0 +@gala-chain/cli/3.0.0 darwin-arm64 node-v24.12.0 $ galachain --help [COMMAND] USAGE $ galachain COMMAND diff --git a/chain-cli/chaincode-template/e2e/__snapshots__/api.spec.ts.snap b/chain-cli/chaincode-template/e2e/__snapshots__/api.spec.ts.snap index 70df2ebc52..fb692717d7 100644 --- a/chain-cli/chaincode-template/e2e/__snapshots__/api.spec.ts.snap +++ b/chain-cli/chaincode-template/e2e/__snapshots__/api.spec.ts.snap @@ -201,7 +201,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { @@ -1661,7 +1661,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { @@ -10424,7 +10424,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { diff --git a/chain-cli/chaincode-template/src/apples/__snapshots__/api.spec.ts.snap b/chain-cli/chaincode-template/src/apples/__snapshots__/api.spec.ts.snap index 49775e4037..23c16ef8e7 100644 --- a/chain-cli/chaincode-template/src/apples/__snapshots__/api.spec.ts.snap +++ b/chain-cli/chaincode-template/src/apples/__snapshots__/api.spec.ts.snap @@ -201,7 +201,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { diff --git a/chain-cli/chaincode-template/src/pk/__snapshots__/api.spec.ts.snap b/chain-cli/chaincode-template/src/pk/__snapshots__/api.spec.ts.snap index aaddcfb83f..6605dbd98c 100644 --- a/chain-cli/chaincode-template/src/pk/__snapshots__/api.spec.ts.snap +++ b/chain-cli/chaincode-template/src/pk/__snapshots__/api.spec.ts.snap @@ -282,7 +282,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { diff --git a/chain-cli/chaincode-template/src/token/__snapshots__/api.spec.ts.snap b/chain-cli/chaincode-template/src/token/__snapshots__/api.spec.ts.snap index f8e1205495..83d7177f60 100644 --- a/chain-cli/chaincode-template/src/token/__snapshots__/api.spec.ts.snap +++ b/chain-cli/chaincode-template/src/token/__snapshots__/api.spec.ts.snap @@ -494,7 +494,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { diff --git a/chaincode/src/contracts/GalaContract.ts b/chaincode/src/contracts/GalaContract.ts index a9cdb789cb..8d05355bce 100644 --- a/chaincode/src/contracts/GalaContract.ts +++ b/chaincode/src/contracts/GalaContract.ts @@ -25,7 +25,6 @@ import { GalaChainResponseType, GetObjectDto, GetObjectHistoryDto, - NotFoundError, UserProfile, ValidationFailedError, createValidDTO, @@ -223,8 +222,7 @@ export abstract class GalaContract extends Contract { in: BatchDto, out: "object", enforceUniqueKey: true, - description: "Submit a batch of transactions", - allowedOrgs: [process.env.CURATOR_ORG_MSP ?? "CuratorOrg"] + description: "Submit a batch of transactions" }) public async BatchSubmit(ctx: GalaChainContext, batchDto: BatchDto): Promise[]> { const responses: GalaChainResponse[] = []; diff --git a/chaincode/src/contracts/GalaTransaction.ts b/chaincode/src/contracts/GalaTransaction.ts index edcd7e83de..3fbdb49863 100644 --- a/chaincode/src/contracts/GalaTransaction.ts +++ b/chaincode/src/contracts/GalaTransaction.ts @@ -138,8 +138,11 @@ function GalaTransaction( } if (options.type === SUBMIT && !options.verifySignature && !options.allowedOrgs?.length) { - const message = `SUBMIT transaction '${propertyKey}' must have either verifySignature or allowedOrgs defined`; - throw new NotImplementedError(message); + // Edge case: we allow BatchSubmit without verifySignature or allowedOrgs + if (propertyKey !== "BatchSubmit") { + const message = `SUBMIT transaction '${propertyKey}' must have either verifySignature or allowedOrgs defined`; + throw new NotImplementedError(message); + } } if (options.allowedRoles !== undefined && options.allowedOrgs !== undefined) { diff --git a/chaincode/src/contracts/__snapshots__/PublicKeyContract.spec.ts.snap b/chaincode/src/contracts/__snapshots__/PublicKeyContract.spec.ts.snap index db0c8e6cf9..e01c5cc8d4 100644 --- a/chaincode/src/contracts/__snapshots__/PublicKeyContract.spec.ts.snap +++ b/chaincode/src/contracts/__snapshots__/PublicKeyContract.spec.ts.snap @@ -283,7 +283,7 @@ The key is generated by the caller and should be unique for each DTO. You can us }, }, { - "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT. Allowed orgs: CuratorOrg.", + "description": "Submit a batch of transactions Transaction updates the chain (submit). Allowed roles: SUBMIT.", "dtoSchema": { "properties": { "dtoExpiresAt": { diff --git a/chaincode/src/contracts/authorize.ts b/chaincode/src/contracts/authorize.ts index 932478c47e..dd91f4f38f 100644 --- a/chaincode/src/contracts/authorize.ts +++ b/chaincode/src/contracts/authorize.ts @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ChainCallDTO, ForbiddenError, UnauthorizedError, UserRole } from "@gala-chain/api"; +import { BatchDto, ChainCallDTO, ForbiddenError, UnauthorizedError, UserRole } from "@gala-chain/api"; import { GalaChainContext } from "../types"; @@ -100,6 +100,13 @@ export function ensureChaincodeIsAllowed(chaincode: string, allowedChaincodes: s } } +function isBatchOperation(ctx: GalaChainContext, dto: ChainCallDTO | undefined) { + const methodName = ctx.operationCtx.methodName; + const isBatchMethod = methodName === "BatchSubmit" || methodName.endsWith(":BatchSubmit"); + const isBatchDto = (dto as BatchDto | undefined)?.operations?.some((o) => o.method.length > 0); + return isBatchMethod || isBatchDto; +} + export interface AuthorizeOptions { allowedOrgs?: string[]; allowedRoles?: string[]; @@ -112,6 +119,11 @@ export async function authorize( options: AuthorizeOptions, dto: ChainCallDTO | undefined ) { + // For batch operations authorization happens for each operation in the batch + if (isBatchOperation(ctx, dto)) { + return; + } + if (options.allowedOriginChaincodes && ctx.callingUser.startsWith("service|")) { const callingChaincode = ctx.callingUser.slice(8); ensureChaincodeIsAllowed(callingChaincode, options.allowedOriginChaincodes); From 6143d15d42453bc748db5a68c390656a92ec2e9e Mon Sep 17 00:00:00 2001 From: Jakub Dzikowski Date: Tue, 7 Apr 2026 09:25:09 +0200 Subject: [PATCH 2/2] Apply suggestion from @dzikowski --- chain-cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain-cli/README.md b/chain-cli/README.md index a12c44e73b..7cc0612715 100644 --- a/chain-cli/README.md +++ b/chain-cli/README.md @@ -20,7 +20,7 @@ $ npm install -g @gala-chain/cli $ galachain COMMAND running command... $ galachain (--version) -@gala-chain/cli/3.0.0 darwin-arm64 node-v24.12.0 +@gala-chain/cli/3.0.0 linux-x64 node-v24.13.0 $ galachain --help [COMMAND] USAGE $ galachain COMMAND