Files
obsidian-jekyll-publish/src/main.ts
Claude 61910acac3
All checks were successful
CI / test (push) Successful in 17s
fix: remove non-portable askpass bridge; rely on native git credentials
The askpass bridge bound a Unix-domain socket to a vault filesystem path
(net.createServer().listen(...sock)). That is invalid on Windows, where
Node's listen() expects a named pipe, so publish aborted with
'listen EACCES: permission denied ...askpass.sock' before git ever ran —
even when the user's git could authenticate. The bridge was non-portable in
general (Windows named pipes; the helper script needs a node binary on PATH).

Remove the bridge and let the user's system git handle credentials via its
native helpers (Git Credential Manager / osxkeychain / libsecret) for https
and ssh-agent for ssh — the 'store nothing' model we already chose.
GIT_TERMINAL_PROMPT=0 stays so git fails fast instead of hanging, and
publish errors now include a credential/identity hint. Deletes askpass.ts
and its test (3 tests); suite 32/32, tsc clean, build OK.

Co-Authored-By: Claude
2026-06-19 03:02:28 +00:00

95 lines
3.5 KiB
TypeScript

import { Notice, Plugin, TFile } from "obsidian";
import { DEFAULT_SETTINGS, JekyllPublishSettings } from "./settings";
import { JekyllPublishSettingTab } from "./SettingsTab";
import { ModalResult, PublishModal } from "./PublishModal";
import { ChildProcessGitClient } from "./git";
import { publish } from "./publish";
export default class JekyllPublishPlugin extends Plugin {
settings!: JekyllPublishSettings;
async onload() {
await this.loadSettings();
this.addSettingTab(new JekyllPublishSettingTab(this.app, this));
this.addCommand({
id: "publish-current-note",
name: "Publish current note to Jekyll",
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!file) return false;
if (!checking) void this.openPublishModal(file);
return true;
},
});
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
private async openPublishModal(file: TFile) {
const noteText = await this.app.vault.read(file);
new PublishModal(this.app, this.settings, noteText, file.basename, (r) =>
void this.runPublish(noteText, r)
).open();
}
private async runPublish(noteText: string, r: ModalResult) {
if (!this.settings.remoteUrl.trim()) {
new Notice("Jekyll Publish: set a remote URL in settings first.");
return;
}
try {
// Credentials are handled entirely by the user's system git: its
// configured credential helper (Git Credential Manager on Windows,
// osxkeychain on macOS, libsecret on Linux) for https:// URLs, or the
// ssh-agent / key for ssh:// URLs. The plugin stores nothing and sets
// GIT_TERMINAL_PROMPT=0 (in ChildProcessGitClient) so git fails fast
// with a clear message instead of hanging when no helper is available.
const git = new ChildProcessGitClient();
const result = await publish(
{ noteText, ...r },
this.settings,
git,
(linktext) => this.resolveImage(linktext)
);
const warn = result.unresolved.length
? ` (${result.unresolved.length} image(s) unresolved)`
: "";
new Notice(`Published ${result.postPath} with ${result.imageCount} image(s)${warn}`);
} catch (e) {
new Notice(`Publish failed: ${withCredentialHint((e as Error).message)}`, 12000);
}
}
private async resolveImage(linktext: string): Promise<Buffer | null> {
const dest = this.app.metadataCache.getFirstLinkpathDest(linktext, "");
if (!dest) return null;
const ab = await this.app.vault.readBinary(dest);
return Buffer.from(ab);
}
}
/**
* When git fails for an authentication reason, append guidance pointing the
* user at their system credential helper / ssh setup, since the plugin
* deliberately does not store or prompt for credentials itself.
*/
function withCredentialHint(message: string): string {
const authPattern =
/could not read (Username|Password)|terminal prompts disabled|Authentication failed|Permission denied|access denied|fatal: Authentication|no email was given|Author identity unknown/i;
if (authPattern.test(message)) {
return (
`${message}\n\n` +
"Git could not authenticate or identify you. For an https:// URL, set up a " +
"git credential helper (e.g. Git Credential Manager). For an ssh:// URL, make " +
"sure your SSH key/agent is configured. You can also set an author name/email " +
"in the plugin settings."
);
}
return message;
}