This is an automated email from the ASF dual-hosted git repository.
thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git
The following commit(s) were added to refs/heads/main by this push:
new ec273dc401f kie-issues#2385: Add commit signing support for Git
operations (#3690)
ec273dc401f is described below
commit ec273dc401f09763815e2c7fb2eb9a1ef07fffdf
Author: Adarsh vk <[email protected]>
AuthorDate: Thu Aug 6 18:22:40 2026 +0530
kie-issues#2385: Add commit signing support for Git operations (#3690)
---
.../src/commitSigner/CommitHistorySigner.ts | 192 +++++++++++++++++++++
.../src/commitSigner/CommitSignerApi.ts | 29 ++++
.../src/commitSigner/SigningArgs.ts | 35 ++++
.../src/context/WorkspacesContext.tsx | 8 +
.../src/context/WorkspacesContextProvider.tsx | 7 +
.../workspaces-git-fs/src/services/GitService.tsx | 5 +
.../src/worker/WorkspacesWorkerApiImpl.ts | 37 +++-
.../src/worker/api/WorkspacesWorkerGitApi.ts | 7 +
8 files changed, 319 insertions(+), 1 deletion(-)
diff --git a/packages/workspaces-git-fs/src/commitSigner/CommitHistorySigner.ts
b/packages/workspaces-git-fs/src/commitSigner/CommitHistorySigner.ts
new file mode 100644
index 00000000000..e41bb56d32e
--- /dev/null
+++ b/packages/workspaces-git-fs/src/commitSigner/CommitHistorySigner.ts
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import git from "isomorphic-git";
+import { KieSandboxWorkspacesFs } from "../services/KieSandboxWorkspaceFs";
+import { SigningArgs, buildSignOptions } from "./SigningArgs";
+
+type ReadCommitResult = Awaited<ReturnType<typeof git.readCommit>>;
+
+/**
+ * Signs existing commits by recreating them with a signature attached.
Recreating a commit changes
+ * its id, so every commit after it is recreated too.
+ */
+export class CommitHistorySigner {
+ public constructor(private readonly args: { fs: KieSandboxWorkspacesFs; dir:
string }) {}
+
+ /**
+ * Signs the commits on `ref` that are not reachable from `until`, and moves
`ref` to the new tip.
+ * It makes no changes when every one of them is already signed, or when
`ref` moved while the
+ * signatures were being produced.
+ */
+ public async signUnpushed(args: {
+ ref: string;
+ author: { name: string; email: string };
+ signing: SigningArgs;
+ until?: string;
+ }): Promise<void> {
+ const { fs, dir } = this.args;
+ const tipAtStart = await git.resolveRef({ fs, dir, ref: args.ref });
+
+ const unpushed = await this.listUnpushedCommits({ ref: args.ref, until:
args.until });
+ if (unpushed === undefined) {
+ return;
+ }
+
+ let oldestUnsignedIndex = -1;
+ for (let i = 0; i < unpushed.length; i++) {
+ if (!unpushed[i].commit.gpgsig) {
+ oldestUnsignedIndex = i;
+ }
+ }
+ if (oldestUnsignedIndex === -1) {
+ return;
+ }
+
+ // `unpushed` is newest first, `recreateCommits` takes oldest first.
+ const newHeadOid = await this.recreateCommits({
+ commits: unpushed.slice(0, oldestUnsignedIndex + 1).reverse(),
+ author: args.author,
+ signing: args.signing,
+ });
+
+ // Stop if `ref` moved while the signatures were being produced.
+ if ((await git.resolveRef({ fs, dir, ref: args.ref })) !== tipAtStart) {
+ return;
+ }
+
+ // `ref` can expand to a ref other than `refs/heads/<branch>`.
+ const pushRef = await git.expandRef({ fs, dir, ref: args.ref });
+ await git.writeRef({ fs, dir, ref: pushRef, value: newHeadOid, force: true
});
+
+ // `depth: 2` yields the branch a symbolic HEAD points at, or an oid when
HEAD is detached.
+ const headRef = await git.resolveRef({ fs, dir, ref: "HEAD", depth: 2 });
+ if (headRef !== pushRef) {
+ const ref = headRef.startsWith("refs/") ? headRef : "HEAD";
+ await git.writeRef({ fs, dir, ref, value: newHeadOid, force: true });
+ }
+ }
+
+ /**
+ * The commits on `ref` that `until` does not already reach, newest first.
Undefined when the point
+ * where the two histories meet cannot be found.
+ */
+ private async listUnpushedCommits(args: { ref: string; until?: string }):
Promise<ReadCommitResult[] | undefined> {
+ const chain = await this.walkFirstParents({ ref: args.ref, stopAt:
args.until });
+ if (args.until === undefined || chain.stoppedAtTarget) {
+ return chain.commits;
+ }
+
+ // The chain missed `until`. The commits it reaches are a suffix of the
chain, so the first one
+ // found searching back from `until` is where the two meet.
+ const boundary = await this.findFirstReachable({
+ from: args.until,
+ targets: new Set(chain.commits.map((entry) => entry.oid)),
+ });
+ if (boundary === undefined) {
+ return undefined;
+ }
+ return chain.commits.slice(
+ 0,
+ chain.commits.findIndex((entry) => entry.oid === boundary)
+ );
+ }
+
+ /**
+ * Walks first parents from `ref`, newest first. `stoppedAtTarget` is true
only when `stopAt` ended
+ * the walk, not when the history ran out.
+ */
+ private async walkFirstParents(args: {
+ ref: string;
+ stopAt?: string;
+ }): Promise<{ commits: ReadCommitResult[]; stoppedAtTarget: boolean }> {
+ const { fs, dir } = this.args;
+ const commits: ReadCommitResult[] = [];
+ let oid: string | undefined = await git.resolveRef({ fs, dir, ref:
args.ref });
+ while (oid !== undefined && oid !== args.stopAt) {
+ let entry: ReadCommitResult;
+ try {
+ entry = await git.readCommit({ fs, dir, oid });
+ } catch {
+ // Not in the local object store, as at the boundary of a shallow
clone.
+ return { commits, stoppedAtTarget: false };
+ }
+ commits.push(entry);
+ oid = entry.commit.parent[0];
+ }
+ return { commits, stoppedAtTarget: oid !== undefined };
+ }
+
+ /**
+ * The first commit reachable from `from` that is in `targets`, searched
breadth first. Undefined
+ * when `from` is missing locally, or when it reaches nothing in `targets`.
+ */
+ private async findFirstReachable(args: { from: string; targets: Set<string>
}): Promise<string | undefined> {
+ const { fs, dir } = this.args;
+ const visited = new Set<string>();
+ const queue: string[] = [args.from];
+ for (let i = 0; i < queue.length; i++) {
+ const oid = queue[i];
+ if (visited.has(oid)) {
+ continue;
+ }
+ visited.add(oid);
+ if (args.targets.has(oid)) {
+ return oid;
+ }
+ try {
+ const entry = await git.readCommit({ fs, dir, oid });
+ queue.push(...entry.commit.parent);
+ } catch {
+ // Not in the local object store, so its parents are unreachable.
+ }
+ }
+ return undefined;
+ }
+
+ /**
+ * Recreates `commits`, ordered oldest first, each keeping its tree, message
and author. A commit
+ * whose author has no email is attributed to `author`. Returns the oid of
the last one.
+ */
+ private async recreateCommits(args: {
+ commits: ReadCommitResult[];
+ author: { name: string; email: string };
+ signing: SigningArgs;
+ }): Promise<string> {
+ const { fs, dir } = this.args;
+ const newOidByOldOid = new Map<string, string>();
+ let newHeadOid = "";
+ for (const entry of args.commits) {
+ const commit = entry.commit;
+ newHeadOid = await git.commit({
+ fs,
+ dir,
+ message: commit.message,
+ tree: commit.tree,
+ parent: commit.parent.map((oid) => newOidByOldOid.get(oid) ?? oid),
+ author: commit.author.email ? commit.author : { ...commit.author,
...args.author },
+ committer: { ...commit.committer, ...args.author },
+ noUpdateBranch: true,
+ ...buildSignOptions(args.signing),
+ });
+ newOidByOldOid.set(entry.oid, newHeadOid);
+ }
+ return newHeadOid;
+ }
+}
diff --git a/packages/workspaces-git-fs/src/commitSigner/CommitSignerApi.ts
b/packages/workspaces-git-fs/src/commitSigner/CommitSignerApi.ts
new file mode 100644
index 00000000000..12a61aa9f36
--- /dev/null
+++ b/packages/workspaces-git-fs/src/commitSigner/CommitSignerApi.ts
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/** The private key used to sign a commit, and the passphrase that unlocks it
when the key is protected. */
+export interface SigningKeyConfig {
+ privateKey: string;
+ passphrase?: string;
+}
+
+/** Signs a commit payload and returns its signature. */
+export interface CommitSigner {
+ sign(args: { payload: string } & SigningKeyConfig): Promise<{ signature:
string }>;
+}
diff --git a/packages/workspaces-git-fs/src/commitSigner/SigningArgs.ts
b/packages/workspaces-git-fs/src/commitSigner/SigningArgs.ts
new file mode 100644
index 00000000000..58c91851f1a
--- /dev/null
+++ b/packages/workspaces-git-fs/src/commitSigner/SigningArgs.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { CommitSigner, SigningKeyConfig } from "./CommitSignerApi";
+
+export interface SigningArgs {
+ signer: CommitSigner;
+ config: SigningKeyConfig;
+}
+
+export function buildSignOptions(signing?: SigningArgs) {
+ if (!signing) {
+ return {};
+ }
+ return {
+ signingKey: signing.config.privateKey,
+ onSign: ({ payload }: { payload: string }) => signing.signer.sign({
payload, ...signing.config }),
+ };
+}
diff --git a/packages/workspaces-git-fs/src/context/WorkspacesContext.tsx
b/packages/workspaces-git-fs/src/context/WorkspacesContext.tsx
index 26a8071b2a4..4430835c0f8 100644
--- a/packages/workspaces-git-fs/src/context/WorkspacesContext.tsx
+++ b/packages/workspaces-git-fs/src/context/WorkspacesContext.tsx
@@ -41,6 +41,7 @@ import { WorkspacesSharedWorker } from
"../worker/WorkspacesSharedWorker";
import { GitServerRef } from "../worker/api/GitServerRef";
import { FetchResult } from "isomorphic-git";
import { UnstagedModifiedFilesStatusEntryType } from "../services/GitService";
+import { SigningKeyConfig } from "../commitSigner/CommitSignerApi";
export class WorkspaceFile {
private readonly parsedRelativePath;
@@ -104,6 +105,8 @@ export interface WorkspacesContextType {
localFiles: LocalFile[];
preferredName?: string;
gitAuthSessionId?: string;
+ gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}) => Promise<{
workspace: WorkspaceDescriptor;
suggestedFirstFile?: WorkspaceFile;
@@ -130,6 +133,7 @@ export interface WorkspacesContextType {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
push(args: {
@@ -144,6 +148,8 @@ export interface WorkspacesContextType {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
deleteBranch(args: { workspaceId: string; ref: string }): Promise<void>;
@@ -184,6 +190,7 @@ export interface WorkspacesContextType {
name: string;
};
commitMessage: string;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
createSavePoint(args: {
@@ -194,6 +201,7 @@ export interface WorkspacesContextType {
};
commitMessage?: string;
forceHasChanges?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
stageFile: (args: { workspaceId: string; relativePath: string }) =>
Promise<void>;
diff --git
a/packages/workspaces-git-fs/src/context/WorkspacesContextProvider.tsx
b/packages/workspaces-git-fs/src/context/WorkspacesContextProvider.tsx
index 665b89d7065..0b721461586 100644
--- a/packages/workspaces-git-fs/src/context/WorkspacesContextProvider.tsx
+++ b/packages/workspaces-git-fs/src/context/WorkspacesContextProvider.tsx
@@ -32,6 +32,7 @@ import {
} from "../worker/api/WorkspaceOrigin";
import { WorkspaceWorkerFileDescriptor } from
"../worker/api/WorkspaceWorkerFileDescriptor";
import { WorkspacesSharedWorker } from "../worker/WorkspacesSharedWorker";
+import { SigningKeyConfig } from "../commitSigner/CommitSignerApi";
type Props = {
children: React.ReactNode;
@@ -113,6 +114,7 @@ export function WorkspacesContextProvider(props: Props) {
authInfo?: { username: string; password: string };
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signingConfig?: SigningKeyConfig;
}) =>
workspacesSharedWorker.withBus((workspacesWorkerBus) =>
workspacesWorkerBus.clientApi.requests.kieSandboxWorkspacesGit_pull(args)
@@ -133,6 +135,8 @@ export function WorkspacesContextProvider(props: Props) {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}) =>
workspacesSharedWorker.withBus((workspacesWorkerBus) => {
return
workspacesWorkerBus.clientApi.requests.kieSandboxWorkspacesGit_push(args);
@@ -217,6 +221,7 @@ export function WorkspacesContextProvider(props: Props) {
targetBranch: string;
commitMessage: string;
gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}) => {
return workspacesSharedWorker.withBus((workspacesWorkerBus) =>
workspacesWorkerBus.clientApi.requests.kieSandboxWorkspacesGit_commit(args)
@@ -231,6 +236,7 @@ export function WorkspacesContextProvider(props: Props) {
gitConfig?: { email: string; name: string };
commitMessage?: string;
forceHasChanges?: boolean;
+ signingConfig?: SigningKeyConfig;
}) => {
if (!args.forceHasChanges && !(await hasLocalChanges(args))) {
return;
@@ -295,6 +301,7 @@ export function WorkspacesContextProvider(props: Props) {
preferredName?: string;
gitAuthSessionId: string | undefined;
gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}) => {
const workspaceInit = await
workspacesSharedWorker.withBus((workspacesWorkerBus) =>
workspacesWorkerBus.clientApi.requests.kieSandboxWorkspacesGit_init(args)
diff --git a/packages/workspaces-git-fs/src/services/GitService.tsx
b/packages/workspaces-git-fs/src/services/GitService.tsx
index f23dca523f1..a116e2217ce 100644
--- a/packages/workspaces-git-fs/src/services/GitService.tsx
+++ b/packages/workspaces-git-fs/src/services/GitService.tsx
@@ -21,6 +21,7 @@ import git, { FetchResult, STAGE, WORKDIR } from
"isomorphic-git";
import http from "isomorphic-git/http/web";
import { GIT_DEFAULT_BRANCH } from "../constants/GitConstants";
import { KieSandboxWorkspacesFs } from "./KieSandboxWorkspaceFs";
+import { SigningArgs, buildSignOptions } from "../commitSigner/SigningArgs";
import { CorsProxyHeaderKeys } from "@kie-tools/cors-proxy-api/dist";
export interface CloneArgs {
@@ -49,6 +50,7 @@ export interface CommitArgs {
name: string;
email: string;
};
+ signing?: SigningArgs;
}
export interface PushArgs {
@@ -243,6 +245,7 @@ export class GitService {
email: args.author.email,
},
ref: args.targetBranch,
+ ...buildSignOptions(args.signing),
});
await git.writeRef({
@@ -268,6 +271,7 @@ export class GitService {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signing?: SigningArgs;
}) {
await git.pull({
fs: args.fs,
@@ -279,6 +283,7 @@ export class GitService {
singleBranch: true,
author: args.author,
onAuth: () => args.authInfo,
+ ...buildSignOptions(args.signing),
});
}
diff --git a/packages/workspaces-git-fs/src/worker/WorkspacesWorkerApiImpl.ts
b/packages/workspaces-git-fs/src/worker/WorkspacesWorkerApiImpl.ts
index 455ecdd935a..8cf37efc42e 100644
--- a/packages/workspaces-git-fs/src/worker/WorkspacesWorkerApiImpl.ts
+++ b/packages/workspaces-git-fs/src/worker/WorkspacesWorkerApiImpl.ts
@@ -28,6 +28,9 @@ import { GIT_DEFAULT_BRANCH } from
"../constants/GitConstants";
import { decoder, encoder } from "../encoderdecoder/EncoderDecoder";
import { FsSchema } from "../services/FsCache";
import { FileModificationStatus, UnstagedModifiedFilesStatusEntryType } from
"../services/GitService";
+import { SigningArgs } from "../commitSigner/SigningArgs";
+import { CommitHistorySigner } from "../commitSigner/CommitHistorySigner";
+import { CommitSigner, SigningKeyConfig } from
"../commitSigner/CommitSignerApi";
import { KieSandboxWorkspacesFs } from "../services/KieSandboxWorkspaceFs";
import { StorageFile } from "../services/StorageService";
import { GitServerRef } from "./api/GitServerRef";
@@ -71,9 +74,15 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
appName: string;
fileFilter: FileFilter;
services: WorkspaceServices;
+ commitSigner?: CommitSigner;
}
) {}
+ private buildSigningArgs(config?: SigningKeyConfig): SigningArgs | undefined
{
+ const signer = this.args.commitSigner;
+ return signer && config ? { signer, config } : undefined;
+ }
+
public async kieSandboxWorkspacesGit_changeGitAuthSessionId(args: {
workspaceId: string;
gitAuthSessionId: string | undefined;
@@ -601,6 +610,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
gitConfig?: { email: string; name: string };
commitMessage: string;
targetBranch: string;
+ signingConfig?: SigningKeyConfig;
}): Promise<void> {
const workspaceRootDirPath =
this.args.services.workspaceService.getAbsolutePath({ workspaceId:
args.workspaceId });
@@ -614,6 +624,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
name: args.gitConfig?.name ?? this.GIT_DEFAULT_USER.name,
email: args.gitConfig?.email ?? this.GIT_DEFAULT_USER.email,
},
+ signing: this.buildSigningArgs(args.signingConfig),
});
});
}
@@ -622,6 +633,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
workspaceId: string;
gitConfig?: { email: string; name: string };
commitMessage?: string;
+ signingConfig?: SigningKeyConfig;
}): Promise<void> {
const descriptor = await
this.args.services.descriptorsFsService.withReadWriteInMemoryFs(({ fs }) => {
return this.args.services.descriptorService.get(fs, args.workspaceId);
@@ -665,6 +677,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
name: args.gitConfig?.name ?? this.GIT_DEFAULT_USER.name,
email: args.gitConfig?.email ?? this.GIT_DEFAULT_USER.email,
},
+ signing: this.buildSigningArgs(args.signingConfig),
});
broadcaster.broadcast({
@@ -704,6 +717,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
gitConfig?: { email: string; name: string };
gitInsecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<{ workspace: WorkspaceDescriptor; suggestedFirstFile?:
WorkspaceWorkerFileDescriptor }> {
return this.createWorkspace({
preferredName: args.preferredName,
@@ -775,6 +789,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
name: args.gitConfig?.name ?? this.GIT_DEFAULT_USER.name,
email: args.gitConfig?.email ?? this.GIT_DEFAULT_USER.email,
},
+ signing: this.buildSigningArgs(args.signingConfig),
});
return
this.args.services.workspaceService.getFilteredWorkspaceFileDescriptors(schema,
workspace.workspaceId);
@@ -788,6 +803,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
authInfo?: { username: string; password: string };
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<void> {
const workspace = await
this.args.services.descriptorsFsService.withReadWriteInMemoryFs(({ fs }) => {
return this.args.services.descriptorService.get(fs, args.workspaceId);
@@ -807,6 +823,7 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
authInfo: args.authInfo,
insecurelyDisableTlsCertificateValidation:
args.insecurelyDisableTlsCertificateValidation,
disableEncoding: args.disableEncoding,
+ signing: this.buildSigningArgs(args.signingConfig),
});
broadcaster.broadcast({
@@ -832,13 +849,31 @@ export class WorkspacesWorkerApiImpl implements
WorkspacesWorkerApi {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}): Promise<void> {
return this.args.services.workspaceFsService.withReadWriteInMemoryFs(
args.workspaceId,
async ({ fs, broadcaster }) => {
+ const dir = this.args.services.workspaceService.getAbsolutePath({
workspaceId: args.workspaceId });
+
+ const signing = this.buildSigningArgs(args.signingConfig);
+ if (signing && args.gitConfig) {
+ const until = await this.args.services.gitService
+ .resolveRef({ fs, dir, ref:
`refs/remotes/${args.remote}/${args.ref}` })
+ .catch(() => undefined);
+
+ await new CommitHistorySigner({ fs, dir }).signUnpushed({
+ ref: args.ref,
+ author: args.gitConfig,
+ signing,
+ until,
+ });
+ }
+
return this.args.services.gitService.push({
fs: fs,
- dir: this.args.services.workspaceService.getAbsolutePath({
workspaceId: args.workspaceId }),
+ dir,
...args,
});
}
diff --git
a/packages/workspaces-git-fs/src/worker/api/WorkspacesWorkerGitApi.ts
b/packages/workspaces-git-fs/src/worker/api/WorkspacesWorkerGitApi.ts
index 31b5ed4450c..1b65f768bfb 100644
--- a/packages/workspaces-git-fs/src/worker/api/WorkspacesWorkerGitApi.ts
+++ b/packages/workspaces-git-fs/src/worker/api/WorkspacesWorkerGitApi.ts
@@ -31,6 +31,7 @@ import { WorkspaceWorkerFileDescriptor } from
"./WorkspaceWorkerFileDescriptor";
import { GitServerRef } from "./GitServerRef";
import { FetchResult } from "isomorphic-git";
import { UnstagedModifiedFilesStatusEntryType } from
"../../services/GitService";
+import { SigningKeyConfig } from "../../commitSigner/CommitSignerApi";
export interface WorkspacesWorkerGitApi {
kieSandboxWorkspacesGit_getGitServerRefs(args: {
@@ -58,6 +59,7 @@ export interface WorkspacesWorkerGitApi {
name: string;
};
gitInsecurelyDisableTlsCertificateValidation?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<{
workspace: WorkspaceDescriptor;
suggestedFirstFile?: WorkspaceWorkerFileDescriptor;
@@ -93,6 +95,7 @@ export interface WorkspacesWorkerGitApi {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
kieSandboxWorkspacesGit_push(args: {
@@ -107,6 +110,8 @@ export interface WorkspacesWorkerGitApi {
};
insecurelyDisableTlsCertificateValidation?: boolean;
disableEncoding?: boolean;
+ gitConfig?: { email: string; name: string };
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
kieSandboxWorkspacesGit_deleteBranch(args: { workspaceId: string; ref:
string }): Promise<void>;
@@ -144,12 +149,14 @@ export interface WorkspacesWorkerGitApi {
name: string;
};
commitMessage?: string;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
kieSandboxWorkspacesGit_createSavePoint(args: {
workspaceId: string;
gitConfig?: { email: string; name: string };
commitMessage?: string;
+ signingConfig?: SigningKeyConfig;
}): Promise<void>;
kieSandboxWorkspacesGit_fetch(args: {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]