fix(nb): additional sops.lua bug fixes

- Use nvim_buf_get_name(args.buf) instead of vim.fn.expand("%:p") in BufReadPost
- Add timeout to encrypt operation to prevent infinite hangs
- Add microsecond precision to temp file names to prevent collisions
- Strip trailing newline before vim.split to avoid extra empty lines
- Add trailing newline when writing temp file for POSIX compliance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-28 01:54:20 +01:00
parent 6935fbea8b
commit 998f04713f

View File

@@ -53,7 +53,7 @@ vim.api.nvim_create_autocmd("BufReadPost", {
group = sops_group, group = sops_group,
pattern = secrets_patterns, pattern = secrets_patterns,
callback = function(args) callback = function(args)
local filepath = vim.fn.expand("%:p") local filepath = vim.api.nvim_buf_get_name(args.buf)
-- Only decrypt if file exists and has content -- Only decrypt if file exists and has content
if vim.fn.filereadable(filepath) == 1 and vim.fn.getfsize(filepath) > 0 then if vim.fn.filereadable(filepath) == 1 and vim.fn.getfsize(filepath) > 0 then
@@ -102,7 +102,8 @@ vim.api.nvim_create_autocmd("BufReadPost", {
detach_lsp_clients(args.buf) detach_lsp_clients(args.buf)
-- Replace buffer content with decrypted content -- Replace buffer content with decrypted content
vim.api.nvim_buf_set_lines(args.buf, 0, -1, false, vim.split(result, "\n")) -- Strip trailing newline to avoid adding extra empty line
vim.api.nvim_buf_set_lines(args.buf, 0, -1, false, vim.split(result:gsub("\n$", ""), "\n"))
-- Mark buffer as not modified (since we just loaded it) -- Mark buffer as not modified (since we just loaded it)
vim.bo[args.buf].modified = false vim.bo[args.buf].modified = false
@@ -165,7 +166,7 @@ vim.api.nvim_create_autocmd("BufWriteCmd", {
-- This avoids /dev/stdin issues while keeping secrets secure (not in /tmp) -- This avoids /dev/stdin issues while keeping secrets secure (not in /tmp)
local dir = vim.fn.fnamemodify(filepath, ":h") local dir = vim.fn.fnamemodify(filepath, ":h")
local filename = vim.fn.fnamemodify(filepath, ":t") local filename = vim.fn.fnamemodify(filepath, ":t")
local temp_file = string.format("%s/.%s.sops_tmp_%d", dir, filename, os.time()) local temp_file = string.format("%s/.%s.sops_tmp_%d_%d", dir, filename, os.time(), vim.loop.hrtime() % 1000000)
-- Write plaintext content to temp file -- Write plaintext content to temp file
local temp_f, temp_err = io.open(temp_file, "w") local temp_f, temp_err = io.open(temp_file, "w")
@@ -173,12 +174,13 @@ vim.api.nvim_create_autocmd("BufWriteCmd", {
vim.notify("SOPS: Failed to create temp file: " .. (temp_err or "unknown error"), vim.log.levels.ERROR) vim.notify("SOPS: Failed to create temp file: " .. (temp_err or "unknown error"), vim.log.levels.ERROR)
return return
end end
temp_f:write(content) temp_f:write(content .. "\n")
temp_f:close() temp_f:close()
-- Encrypt temp file with filename override so SOPS matches .sops.yaml rules -- Encrypt temp file with filename override so SOPS matches .sops.yaml rules
-- Uses real filepath for rule matching, temp file for content -- Uses real filepath for rule matching, temp file for content
local cmd = string.format("sops --encrypt --filename-override %s %s", local cmd = string.format("timeout %d sops --encrypt --filename-override %s %s",
SOPS_TIMEOUT,
vim.fn.shellescape(filepath), vim.fn.shellescape(filepath),
vim.fn.shellescape(temp_file)) vim.fn.shellescape(temp_file))
local encrypted = vim.fn.system(cmd) local encrypted = vim.fn.system(cmd)
@@ -187,6 +189,15 @@ vim.api.nvim_create_autocmd("BufWriteCmd", {
-- Always clean up temp file, even on error -- Always clean up temp file, even on error
os.remove(temp_file) os.remove(temp_file)
-- Check for timeout (exit code 124 from timeout command)
if sops_exit_code == 124 then
vim.notify(
string.format("SOPS: Encryption timed out after %d seconds.", SOPS_TIMEOUT),
vim.log.levels.ERROR
)
return
end
if sops_exit_code == 0 then if sops_exit_code == 0 then
-- Write encrypted content directly to file -- Write encrypted content directly to file
local file, file_err = io.open(filepath, "w") local file, file_err = io.open(filepath, "w")
@@ -212,7 +223,8 @@ vim.api.nvim_create_autocmd("BufWriteCmd", {
detach_lsp_clients(args.buf) detach_lsp_clients(args.buf)
-- Replace buffer with decrypted content -- Replace buffer with decrypted content
vim.api.nvim_buf_set_lines(args.buf, 0, -1, false, vim.split(decrypted, "\n")) -- Strip trailing newline to avoid adding extra empty line
vim.api.nvim_buf_set_lines(args.buf, 0, -1, false, vim.split(decrypted:gsub("\n$", ""), "\n"))
-- Mark as not modified since we just saved -- Mark as not modified since we just saved
vim.bo[args.buf].modified = false vim.bo[args.buf].modified = false