mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(secure): add :trust
command and vim.secure.trust() (#21107)
Introduce vim.secure.trust() to programmatically manage the trust database. Use this function in a new :trust ex command which can be used as a simple frontend. Resolves: https://github.com/neovim/neovim/issues/21092 Co-authored-by: Gregory Anders <greg@gpanders.com> Co-authored-by: ii14 <ii14@users.noreply.github.com>
This commit is contained in:
parent
77a0f4a542
commit
f004812b33
@ -1650,4 +1650,32 @@ There are three different types of searching:
|
|||||||
currently work with 'path' items that contain a URL or use the double star
|
currently work with 'path' items that contain a URL or use the double star
|
||||||
with depth limiter (/usr/**2) or upward search (;) notations.
|
with depth limiter (/usr/**2) or upward search (;) notations.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
11. Trusted Files *trust*
|
||||||
|
|
||||||
|
Nvim has the ability to execute arbitrary code through the 'exrc' option. In
|
||||||
|
order to prevent executing code from untrusted sources, Nvim has the concept of
|
||||||
|
"trusted files". An untrusted file will not be executed without the user's
|
||||||
|
consent, and a user can permanently mark a file as trusted or untrusted using
|
||||||
|
the |:trust| command or the |vim.secure.read()| function.
|
||||||
|
|
||||||
|
*:trust* *E5570*
|
||||||
|
:trust [++deny] [++remove] [{file}]
|
||||||
|
|
||||||
|
Manage files in the trust database. Without any options
|
||||||
|
or arguments, :trust adds the file associated with the
|
||||||
|
current buffer to the trust database, along with the
|
||||||
|
SHA256 hash of its contents.
|
||||||
|
|
||||||
|
[++deny] marks the file associated with the current
|
||||||
|
buffer (or {file}, if given) as denied; no prompts will
|
||||||
|
be displayed to the user and the file will never be
|
||||||
|
executed.
|
||||||
|
|
||||||
|
[++remove] removes the file associated with the current
|
||||||
|
buffer (or {file}, if given) from the trust database.
|
||||||
|
Future attempts to read the file in a secure setting
|
||||||
|
(i.e. with 'exrc' or |vim.secure.read()|) will prompt
|
||||||
|
the user if the file is trusted.
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
@ -1633,6 +1633,7 @@ tag command action ~
|
|||||||
|:topleft| :to[pleft] make split window appear at top or far left
|
|:topleft| :to[pleft] make split window appear at top or far left
|
||||||
|:tprevious| :tp[revious] jump to previous matching tag
|
|:tprevious| :tp[revious] jump to previous matching tag
|
||||||
|:trewind| :tr[ewind] jump to first matching tag
|
|:trewind| :tr[ewind] jump to first matching tag
|
||||||
|
|:trust| :trust add or remove file from trust database
|
||||||
|:try| :try execute commands, abort on error or exception
|
|:try| :try execute commands, abort on error or exception
|
||||||
|:tselect| :ts[elect] list matching tags and select one
|
|:tselect| :ts[elect] list matching tags and select one
|
||||||
|:tunmap| :tunma[p] like ":unmap" but for |Terminal-mode|
|
|:tunmap| :tunma[p] like ":unmap" but for |Terminal-mode|
|
||||||
|
@ -2371,4 +2371,28 @@ read({path}) *vim.secure.read()*
|
|||||||
(string|nil) The contents of the given file if it exists and is
|
(string|nil) The contents of the given file if it exists and is
|
||||||
trusted, or nil otherwise.
|
trusted, or nil otherwise.
|
||||||
|
|
||||||
|
See also: ~
|
||||||
|
|:trust|
|
||||||
|
|
||||||
|
trust({opts}) *vim.secure.trust()*
|
||||||
|
Manage the trust database.
|
||||||
|
|
||||||
|
The trust database is located at |$XDG_STATE_HOME|/nvim/trust.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
• {opts} (table)
|
||||||
|
• action (string): "allow" to add a file to the trust database
|
||||||
|
and trust it, "deny" to add a file to the trust database and
|
||||||
|
deny it, "remove" to remove file from the trust database
|
||||||
|
• path (string|nil): Path to a file to update. Mutually
|
||||||
|
exclusive with {bufnr}. Cannot be used when {action} is
|
||||||
|
"allow".
|
||||||
|
• bufnr (number|nil): Buffer number to update. Mutually
|
||||||
|
exclusive with {path}.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
(boolean, string) success, msg:
|
||||||
|
• true and full path of target file if operation was successful
|
||||||
|
• false and error message on failure
|
||||||
|
|
||||||
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
|
||||||
|
@ -39,6 +39,9 @@ NEW FEATURES *news-features*
|
|||||||
|
|
||||||
The following new APIs or features were added.
|
The following new APIs or features were added.
|
||||||
|
|
||||||
|
• |vim.secure.trust()|, |:trust| allows the user to manage files in trust
|
||||||
|
database.
|
||||||
|
|
||||||
• |vim.diagnostic.open_float()| (and therefore |vim.diagnostic.config()|) now
|
• |vim.diagnostic.open_float()| (and therefore |vim.diagnostic.config()|) now
|
||||||
accepts a `suffix` option which, by default, renders LSP error codes.
|
accepts a `suffix` option which, by default, renders LSP error codes.
|
||||||
Similarly, the `virtual_text` configuration in |vim.diagnostic.config()| now
|
Similarly, the `virtual_text` configuration in |vim.diagnostic.config()| now
|
||||||
|
@ -2275,6 +2275,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
file are persisted to a trust database. The user is only prompted
|
file are persisted to a trust database. The user is only prompted
|
||||||
again if the file contents change. See |vim.secure.read()|.
|
again if the file contents change. See |vim.secure.read()|.
|
||||||
|
|
||||||
|
Use |:trust| to manage the trusted file database.
|
||||||
|
|
||||||
This option cannot be set from a |modeline| or in the |sandbox|, for
|
This option cannot be set from a |modeline| or in the |sandbox|, for
|
||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
|
@ -1,9 +1,50 @@
|
|||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
|
---@private
|
||||||
|
--- Reads trust database from $XDG_STATE_HOME/nvim/trust.
|
||||||
|
---
|
||||||
|
---@return (table) Contents of trust database, if it exists. Empty table otherwise.
|
||||||
|
local function read_trust()
|
||||||
|
local trust = {}
|
||||||
|
local f = io.open(vim.fn.stdpath('state') .. '/trust', 'r')
|
||||||
|
if f then
|
||||||
|
local contents = f:read('*a')
|
||||||
|
if contents then
|
||||||
|
for line in vim.gsplit(contents, '\n') do
|
||||||
|
local hash, file = string.match(line, '^(%S+) (.+)$')
|
||||||
|
if hash and file then
|
||||||
|
trust[file] = hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
return trust
|
||||||
|
end
|
||||||
|
|
||||||
|
---@private
|
||||||
|
--- Writes provided {trust} table to trust database at
|
||||||
|
--- $XDG_STATE_HOME/nvim/trust.
|
||||||
|
---
|
||||||
|
---@param trust (table) Trust table to write
|
||||||
|
local function write_trust(trust)
|
||||||
|
vim.validate({ trust = { trust, 't' } })
|
||||||
|
local f = assert(io.open(vim.fn.stdpath('state') .. '/trust', 'w'))
|
||||||
|
|
||||||
|
local t = {}
|
||||||
|
for p, h in pairs(trust) do
|
||||||
|
t[#t + 1] = string.format('%s %s\n', h, p)
|
||||||
|
end
|
||||||
|
f:write(table.concat(t))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
--- Attempt to read the file at {path} prompting the user if the file should be
|
--- Attempt to read the file at {path} prompting the user if the file should be
|
||||||
--- trusted. The user's choice is persisted in a trust database at
|
--- trusted. The user's choice is persisted in a trust database at
|
||||||
--- $XDG_STATE_HOME/nvim/trust.
|
--- $XDG_STATE_HOME/nvim/trust.
|
||||||
---
|
---
|
||||||
|
---@see |:trust|
|
||||||
|
---
|
||||||
---@param path (string) Path to a file to read.
|
---@param path (string) Path to a file to read.
|
||||||
---
|
---
|
||||||
---@return (string|nil) The contents of the given file if it exists and is
|
---@return (string|nil) The contents of the given file if it exists and is
|
||||||
@ -15,22 +56,7 @@ function M.read(path)
|
|||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local trust = {}
|
local trust = read_trust()
|
||||||
do
|
|
||||||
local f = io.open(vim.fn.stdpath('state') .. '/trust', 'r')
|
|
||||||
if f then
|
|
||||||
local contents = f:read('*a')
|
|
||||||
if contents then
|
|
||||||
for line in vim.gsplit(contents, '\n') do
|
|
||||||
local hash, file = string.match(line, '^(%S+) (.+)$')
|
|
||||||
if hash and file then
|
|
||||||
trust[file] = hash
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if trust[fullpath] == '!' then
|
if trust[fullpath] == '!' then
|
||||||
-- File is denied
|
-- File is denied
|
||||||
@ -86,21 +112,82 @@ function M.read(path)
|
|||||||
trust[fullpath] = hash
|
trust[fullpath] = hash
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
write_trust(trust)
|
||||||
local f, err = io.open(vim.fn.stdpath('state') .. '/trust', 'w')
|
|
||||||
if not f then
|
|
||||||
error(err)
|
|
||||||
end
|
|
||||||
|
|
||||||
local t = {}
|
|
||||||
for p, h in pairs(trust) do
|
|
||||||
t[#t + 1] = string.format('%s %s\n', h, p)
|
|
||||||
end
|
|
||||||
f:write(table.concat(t))
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
return contents
|
return contents
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Manage the trust database.
|
||||||
|
---
|
||||||
|
--- The trust database is located at |$XDG_STATE_HOME|/nvim/trust.
|
||||||
|
---
|
||||||
|
---@param opts (table):
|
||||||
|
--- - action (string): "allow" to add a file to the trust database and trust it,
|
||||||
|
--- "deny" to add a file to the trust database and deny it,
|
||||||
|
--- "remove" to remove file from the trust database
|
||||||
|
--- - path (string|nil): Path to a file to update. Mutually exclusive with {bufnr}.
|
||||||
|
--- Cannot be used when {action} is "allow".
|
||||||
|
--- - bufnr (number|nil): Buffer number to update. Mutually exclusive with {path}.
|
||||||
|
---@return (boolean, string) success, msg:
|
||||||
|
--- - true and full path of target file if operation was successful
|
||||||
|
--- - false and error message on failure
|
||||||
|
function M.trust(opts)
|
||||||
|
vim.validate({
|
||||||
|
path = { opts.path, 's', true },
|
||||||
|
bufnr = { opts.bufnr, 'n', true },
|
||||||
|
action = {
|
||||||
|
opts.action,
|
||||||
|
function(m)
|
||||||
|
return m == 'allow' or m == 'deny' or m == 'remove'
|
||||||
|
end,
|
||||||
|
[["allow" or "deny" or "remove"]],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
local path = opts.path
|
||||||
|
local bufnr = opts.bufnr
|
||||||
|
local action = opts.action
|
||||||
|
|
||||||
|
if path and bufnr then
|
||||||
|
error('path and bufnr are mutually exclusive', 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
local fullpath
|
||||||
|
if path then
|
||||||
|
fullpath = vim.loop.fs_realpath(vim.fs.normalize(path))
|
||||||
|
else
|
||||||
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
if bufname == '' then
|
||||||
|
return false, 'buffer is not associated with a file'
|
||||||
|
end
|
||||||
|
fullpath = vim.loop.fs_realpath(vim.fs.normalize(bufname))
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fullpath then
|
||||||
|
return false, string.format('invalid path: %s', path)
|
||||||
|
end
|
||||||
|
|
||||||
|
local trust = read_trust()
|
||||||
|
|
||||||
|
if action == 'allow' then
|
||||||
|
assert(bufnr, 'bufnr is required when action is "allow"')
|
||||||
|
|
||||||
|
local newline = vim.bo[bufnr].fileformat == 'unix' and '\n' or '\r\n'
|
||||||
|
local contents = table.concat(vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), newline)
|
||||||
|
if vim.bo[bufnr].endofline then
|
||||||
|
contents = contents .. newline
|
||||||
|
end
|
||||||
|
local hash = vim.fn.sha256(contents)
|
||||||
|
|
||||||
|
trust[fullpath] = hash
|
||||||
|
elseif action == 'deny' then
|
||||||
|
trust[fullpath] = '!'
|
||||||
|
elseif action == 'remove' then
|
||||||
|
trust[fullpath] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
write_trust(trust)
|
||||||
|
return true, fullpath
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "nvim/highlight_group.h"
|
#include "nvim/highlight_group.h"
|
||||||
#include "nvim/indent.h"
|
#include "nvim/indent.h"
|
||||||
#include "nvim/input.h"
|
#include "nvim/input.h"
|
||||||
|
#include "nvim/lua/executor.h"
|
||||||
#include "nvim/macros.h"
|
#include "nvim/macros.h"
|
||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
@ -4960,3 +4961,29 @@ void ex_oldfiles(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ex_trust(exarg_T *eap)
|
||||||
|
{
|
||||||
|
const char *const p = skiptowhite(eap->arg);
|
||||||
|
char *arg1 = xmemdupz(eap->arg, (size_t)(p - eap->arg));
|
||||||
|
const char *action = "allow";
|
||||||
|
const char *path = skipwhite(p);
|
||||||
|
|
||||||
|
if (strcmp(arg1, "++deny") == 0) {
|
||||||
|
action = "deny";
|
||||||
|
} else if (strcmp(arg1, "++remove") == 0) {
|
||||||
|
action = "remove";
|
||||||
|
} else if (*arg1 != '\0') {
|
||||||
|
semsg(e_invarg2, arg1);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path[0] == '\0') {
|
||||||
|
path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlua_trust(action, path);
|
||||||
|
|
||||||
|
theend:
|
||||||
|
xfree(arg1);
|
||||||
|
}
|
||||||
|
@ -2933,6 +2933,12 @@ module.cmds = {
|
|||||||
addr_type='ADDR_OTHER',
|
addr_type='ADDR_OTHER',
|
||||||
func='ex_tag',
|
func='ex_tag',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command='trust',
|
||||||
|
flags=bit.bor(EXTRA, FILE1, TRLBAR, LOCK_OK),
|
||||||
|
addr_type='ADDR_NONE',
|
||||||
|
func='ex_trust',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
command='try',
|
command='try',
|
||||||
flags=bit.bor(TRLBAR, SBOXOK, CMDWIN, LOCK_OK),
|
flags=bit.bor(TRLBAR, SBOXOK, CMDWIN, LOCK_OK),
|
||||||
|
@ -1827,6 +1827,7 @@ static bool skip_cmd(const exarg_T *eap)
|
|||||||
case CMD_throw:
|
case CMD_throw:
|
||||||
case CMD_tilde:
|
case CMD_tilde:
|
||||||
case CMD_topleft:
|
case CMD_topleft:
|
||||||
|
case CMD_trust:
|
||||||
case CMD_unlet:
|
case CMD_unlet:
|
||||||
case CMD_unlockvar:
|
case CMD_unlockvar:
|
||||||
case CMD_verbose:
|
case CMD_verbose:
|
||||||
|
@ -1016,6 +1016,8 @@ EXTERN char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group
|
|||||||
EXTERN char e_undobang_cannot_redo_or_move_branch[]
|
EXTERN char e_undobang_cannot_redo_or_move_branch[]
|
||||||
INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
|
INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch"));
|
||||||
|
|
||||||
|
EXTERN char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s"));
|
||||||
|
|
||||||
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
|
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
|
||||||
EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
|
EXTERN char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP"));
|
||||||
|
|
||||||
|
@ -2217,3 +2217,51 @@ char *nlua_read_secure(const char *path)
|
|||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nlua_trust(const char *action, const char *path)
|
||||||
|
{
|
||||||
|
lua_State *const lstate = global_lstate;
|
||||||
|
lua_getglobal(lstate, "vim");
|
||||||
|
lua_getfield(lstate, -1, "secure");
|
||||||
|
lua_getfield(lstate, -1, "trust");
|
||||||
|
|
||||||
|
lua_newtable(lstate);
|
||||||
|
lua_pushstring(lstate, "action");
|
||||||
|
lua_pushstring(lstate, action);
|
||||||
|
lua_settable(lstate, -3);
|
||||||
|
if (path == NULL) {
|
||||||
|
lua_pushstring(lstate, "bufnr");
|
||||||
|
lua_pushnumber(lstate, 0);
|
||||||
|
lua_settable(lstate, -3);
|
||||||
|
} else {
|
||||||
|
lua_pushstring(lstate, "path");
|
||||||
|
lua_pushstring(lstate, path);
|
||||||
|
lua_settable(lstate, -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nlua_pcall(lstate, 1, 2)) {
|
||||||
|
nlua_error(lstate, _("Error executing vim.secure.trust: %.*s"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = lua_toboolean(lstate, -2);
|
||||||
|
const char *msg = lua_tostring(lstate, -1);
|
||||||
|
if (msg != NULL) {
|
||||||
|
if (success) {
|
||||||
|
if (strcmp(action, "allow") == 0) {
|
||||||
|
smsg("Allowed \"%s\" in trust database.", msg);
|
||||||
|
} else if (strcmp(action, "deny") == 0) {
|
||||||
|
smsg("Denied \"%s\" in trust database.", msg);
|
||||||
|
} else if (strcmp(action, "remove") == 0) {
|
||||||
|
smsg("Removed \"%s\" from trust database.", msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
semsg(e_trustfile, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop return values, "vim" and "secure"
|
||||||
|
lua_pop(lstate, 4);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
176
test/functional/ex_cmds/trust_spec.lua
Normal file
176
test/functional/ex_cmds/trust_spec.lua
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
|
||||||
|
local eq = helpers.eq
|
||||||
|
local clear = helpers.clear
|
||||||
|
local command = helpers.command
|
||||||
|
local pathsep = helpers.get_pathsep()
|
||||||
|
local is_os = helpers.is_os
|
||||||
|
local funcs = helpers.funcs
|
||||||
|
|
||||||
|
describe(':trust', function()
|
||||||
|
local xstate = 'Xstate'
|
||||||
|
|
||||||
|
setup(function()
|
||||||
|
helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
teardown(function()
|
||||||
|
helpers.rmdir(xstate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
helpers.write_file('test_file', 'test')
|
||||||
|
clear{env={XDG_STATE_HOME=xstate}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
os.remove('test_file')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('trust then deny then remove a file using current buffer', function()
|
||||||
|
local screen = Screen.new(80, 8)
|
||||||
|
screen:attach()
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
})
|
||||||
|
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
command('trust')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust))
|
||||||
|
|
||||||
|
command('trust ++deny')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
|
||||||
|
|
||||||
|
command('trust ++remove')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format(''), vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('deny then trust then remove a file using current buffer', function()
|
||||||
|
local screen = Screen.new(80, 8)
|
||||||
|
screen:attach()
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
})
|
||||||
|
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
command('trust ++deny')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
|
||||||
|
|
||||||
|
command('trust')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" trusted.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, cwd .. pathsep .. 'test_file'), vim.trim(trust))
|
||||||
|
|
||||||
|
command('trust ++remove')
|
||||||
|
screen:expect([[
|
||||||
|
^test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format(''), vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('deny then remove a file using file path', function()
|
||||||
|
local screen = Screen.new(80, 8)
|
||||||
|
screen:attach()
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
[1] = {bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
})
|
||||||
|
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
|
||||||
|
command('trust ++deny test_file')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" denied.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', cwd .. pathsep .. 'test_file'), vim.trim(trust))
|
||||||
|
|
||||||
|
command('trust ++remove test_file')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
"]] .. cwd .. pathsep .. [[test_file" removed.{MATCH:%s+}|
|
||||||
|
]])
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format(''), vim.trim(trust))
|
||||||
|
end)
|
||||||
|
end)
|
@ -168,4 +168,111 @@ describe('vim.secure', function()
|
|||||||
eq(false, curbufmeths.get_option('modifiable'))
|
eq(false, curbufmeths.get_option('modifiable'))
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('trust()', function()
|
||||||
|
local xstate = 'Xstate'
|
||||||
|
|
||||||
|
setup(function()
|
||||||
|
helpers.mkdir_p(xstate .. pathsep .. (is_os('win') and 'nvim-data' or 'nvim'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
teardown(function()
|
||||||
|
helpers.rmdir(xstate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
helpers.write_file('test_file', 'test')
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
os.remove('test_file')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('returns error when passing both path and bufnr', function()
|
||||||
|
eq('path and bufnr are mutually exclusive',
|
||||||
|
pcall_err(exec_lua, [[vim.secure.trust({action='deny', bufnr=0, path='test_file'})]]))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('trust then deny then remove a file using bufnr', function()
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
local full_path = cwd .. pathsep .. 'test_file'
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq('', vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('deny then trust then remove a file using bufnr', function()
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
local full_path = cwd .. pathsep .. 'test_file'
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', bufnr=0})}]]))
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', bufnr=0})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq('', vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('trust using bufnr then deny then remove a file using path', function()
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
local full_path = cwd .. pathsep .. 'test_file'
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq('', vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('deny then trust then remove a file using bufnr', function()
|
||||||
|
local cwd = funcs.getcwd()
|
||||||
|
local hash = funcs.sha256(helpers.read_file('test_file'))
|
||||||
|
local full_path = cwd .. pathsep .. 'test_file'
|
||||||
|
|
||||||
|
command('edit test_file')
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='deny', path='test_file'})}]]))
|
||||||
|
local trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('! %s', full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq(string.format('%s %s', hash, full_path), vim.trim(trust))
|
||||||
|
|
||||||
|
eq({true, full_path}, exec_lua([[return {vim.secure.trust({action='remove', path='test_file'})}]]))
|
||||||
|
trust = helpers.read_file(funcs.stdpath('state') .. pathsep .. 'trust')
|
||||||
|
eq('', vim.trim(trust))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('trust returns error when buffer not associated to file', function()
|
||||||
|
command('new')
|
||||||
|
eq({false, 'buffer is not associated with a file'},
|
||||||
|
exec_lua([[return {vim.secure.trust({action='allow', bufnr=0})}]]))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user