mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
feat(exrc): user must view and explicitly run ":trust" #35069
Problem: It's relatively easy to mispress key `a` to (a)llow arbitrary execution of 'exrc' files. #35050 Solution: - For exrc files (not directories), remove "allow" menu item. Require the user to "view" and then explicitly `:trust` the file.
This commit is contained in:
@@ -63,7 +63,10 @@ DIAGNOSTICS
|
|||||||
|
|
||||||
EDITOR
|
EDITOR
|
||||||
|
|
||||||
• todo
|
• |vim.secure.read()| now removes the choice "(a)llow" from the prompt reply for
|
||||||
|
files unlisted in the user's trust database, and thus requires the user to
|
||||||
|
choose (v)iew then run `:trust`. Previously the user would be able to press
|
||||||
|
the single key 'a' to execute the arbitrary execution immediately.
|
||||||
|
|
||||||
EVENTS
|
EVENTS
|
||||||
|
|
||||||
|
@@ -121,18 +121,16 @@ function M.read(path)
|
|||||||
return contents
|
return contents
|
||||||
end
|
end
|
||||||
|
|
||||||
local dir_msg = ''
|
local dir_msg = ' To enable it, choose (v)iew then run `:trust`.'
|
||||||
|
local choices = '&ignore\n&view\n&deny'
|
||||||
if hash == 'directory' then
|
if hash == 'directory' then
|
||||||
dir_msg = ' DIRECTORY trust is decided only by its name, not its contents.'
|
dir_msg = ' DIRECTORY trust is decided only by its name, not its contents.'
|
||||||
|
choices = '&ignore\n&view\n&deny\n&allow'
|
||||||
end
|
end
|
||||||
|
|
||||||
-- File either does not exist in trust database or the hash does not match
|
-- File either does not exist in trust database or the hash does not match
|
||||||
local ok, result = pcall(
|
local ok, result =
|
||||||
vim.fn.confirm,
|
pcall(vim.fn.confirm, string.format('%s is not trusted.%s', fullpath, dir_msg), choices, 1)
|
||||||
string.format('%s is not trusted.%s', fullpath, dir_msg),
|
|
||||||
'&ignore\n&view\n&deny\n&allow',
|
|
||||||
1
|
|
||||||
)
|
|
||||||
|
|
||||||
if not ok and result ~= 'Keyboard interrupt' then
|
if not ok and result ~= 'Keyboard interrupt' then
|
||||||
error(result)
|
error(result)
|
||||||
@@ -147,7 +145,7 @@ function M.read(path)
|
|||||||
-- Deny
|
-- Deny
|
||||||
trust[fullpath] = '!'
|
trust[fullpath] = '!'
|
||||||
contents = nil
|
contents = nil
|
||||||
elseif result == 4 then
|
elseif hash == 'directory' and result == 4 then
|
||||||
-- Allow
|
-- Allow
|
||||||
trust[fullpath] = hash
|
trust[fullpath] = hash
|
||||||
end
|
end
|
||||||
|
@@ -1200,9 +1200,11 @@ describe('user config init', function()
|
|||||||
VIMRUNTIME = os.getenv('VIMRUNTIME'),
|
VIMRUNTIME = os.getenv('VIMRUNTIME'),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny, (a)llow:') })
|
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny:') })
|
||||||
-- `i` to enter Terminal mode, `a` to allow
|
-- `i` to enter Terminal mode, `v` to view then `:trust`
|
||||||
feed('ia')
|
feed('iv')
|
||||||
|
feed(':trust<CR>')
|
||||||
|
feed(':q<CR>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
^ |
|
^ |
|
||||||
~ |*4
|
~ |*4
|
||||||
@@ -1219,8 +1221,8 @@ describe('user config init', function()
|
|||||||
%s%s|
|
%s%s|
|
||||||
-- TERMINAL -- |
|
-- TERMINAL -- |
|
||||||
]],
|
]],
|
||||||
filename,
|
'---',
|
||||||
string.rep(' ', 50 - #filename)
|
string.rep(' ', 50 - #'---')
|
||||||
))
|
))
|
||||||
|
|
||||||
clear { args_rm = { '-u' }, env = xstateenv }
|
clear { args_rm = { '-u' }, env = xstateenv }
|
||||||
@@ -1239,7 +1241,8 @@ describe('user config init', function()
|
|||||||
setup_exrc_file('.nvim.lua')
|
setup_exrc_file('.nvim.lua')
|
||||||
setup_exrc_file('../.exrc')
|
setup_exrc_file('../.exrc')
|
||||||
clear { args_rm = { '-u' }, env = xstateenv }
|
clear { args_rm = { '-u' }, env = xstateenv }
|
||||||
local screen = Screen.new(50, 8)
|
-- use a screen wide width to avoid wrapping the word `.exrc`, `.nvim.lua` below.
|
||||||
|
local screen = Screen.new(500, 8)
|
||||||
screen._default_attr_ids = nil
|
screen._default_attr_ids = nil
|
||||||
fn.jobstart({ nvim_prog }, {
|
fn.jobstart({ nvim_prog }, {
|
||||||
term = true,
|
term = true,
|
||||||
@@ -1249,13 +1252,36 @@ describe('user config init', function()
|
|||||||
})
|
})
|
||||||
-- current directory exrc is found first
|
-- current directory exrc is found first
|
||||||
screen:expect({ any = '.nvim.lua' })
|
screen:expect({ any = '.nvim.lua' })
|
||||||
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny, (a)llow:'), unchanged = true })
|
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny:'), unchanged = true })
|
||||||
feed('ia')
|
feed('iv')
|
||||||
|
|
||||||
-- after that the exrc in the parent directory
|
-- after that the exrc in the parent directory
|
||||||
screen:expect({ any = '.exrc' })
|
screen:expect({ any = '.exrc', unchanged = true })
|
||||||
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny, (a)llow:'), unchanged = true })
|
screen:expect({ any = pesc('[i]gnore, (v)iew, (d)eny:'), unchanged = true })
|
||||||
feed('a')
|
feed('v')
|
||||||
|
|
||||||
|
-- trust .exrc
|
||||||
|
feed(':trust<CR>')
|
||||||
|
screen:expect({ any = 'Allowed ".*' .. pathsep .. '%.exrc" in trust database.' })
|
||||||
|
feed(':q<CR>')
|
||||||
|
-- trust .nvim.lua
|
||||||
|
feed(':trust<CR>')
|
||||||
|
screen:expect({ any = 'Allowed ".*' .. pathsep .. '%.nvim%.lua" in trust database.' })
|
||||||
|
feed(':q<CR>')
|
||||||
|
-- no exrc file is executed
|
||||||
|
feed(':echo g:exrc_count<CR>')
|
||||||
|
screen:expect({ any = 'E121: Undefined variable: g:exrc_count' })
|
||||||
|
|
||||||
|
-- restart nvim
|
||||||
|
feed(':restart<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
^{MATCH: +}|
|
||||||
|
~{MATCH: +}|*4
|
||||||
|
[No Name]{MATCH: +}0,0-1{MATCH: +}All|
|
||||||
|
{MATCH: +}|
|
||||||
|
-- TERMINAL --{MATCH: +}|
|
||||||
|
]])
|
||||||
|
|
||||||
-- a total of 2 exrc files are executed
|
-- a total of 2 exrc files are executed
|
||||||
feed(':echo g:exrc_count<CR>')
|
feed(':echo g:exrc_count<CR>')
|
||||||
screen:expect({ any = '2' })
|
screen:expect({ any = '2' })
|
||||||
|
@@ -55,7 +55,9 @@ describe('vim.secure', function()
|
|||||||
})
|
})
|
||||||
|
|
||||||
local cwd = fn.getcwd()
|
local cwd = fn.getcwd()
|
||||||
local msg = cwd .. pathsep .. 'Xfile is not trusted.'
|
local msg = cwd
|
||||||
|
.. pathsep
|
||||||
|
.. 'Xfile is not trusted. To enable it, choose (v)iew then run `:trust`.'
|
||||||
if #msg >= screen._width then
|
if #msg >= screen._width then
|
||||||
pending('path too long')
|
pending('path too long')
|
||||||
return
|
return
|
||||||
@@ -69,7 +71,7 @@ describe('vim.secure', function()
|
|||||||
{2:{MATCH: +}}|
|
{2:{MATCH: +}}|
|
||||||
:lua vim.secure.read('Xfile'){MATCH: +}|
|
:lua vim.secure.read('Xfile'){MATCH: +}|
|
||||||
{3:]] .. msg .. [[}{MATCH: +}|
|
{3:]] .. msg .. [[}{MATCH: +}|
|
||||||
{3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}|
|
{3:[i]gnore, (v)iew, (d)eny: }^{MATCH: +}|
|
||||||
]])
|
]])
|
||||||
feed('d')
|
feed('d')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
@@ -91,14 +93,21 @@ describe('vim.secure', function()
|
|||||||
{2:{MATCH: +}}|
|
{2:{MATCH: +}}|
|
||||||
:lua vim.secure.read('Xfile'){MATCH: +}|
|
:lua vim.secure.read('Xfile'){MATCH: +}|
|
||||||
{3:]] .. msg .. [[}{MATCH: +}|
|
{3:]] .. msg .. [[}{MATCH: +}|
|
||||||
{3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}|
|
{3:[i]gnore, (v)iew, (d)eny: }^{MATCH: +}|
|
||||||
]])
|
]])
|
||||||
feed('a')
|
feed('v')
|
||||||
|
feed(':trust<CR>')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
^{MATCH: +}|
|
^let g:foobar = 42{MATCH: +}|
|
||||||
{1:~{MATCH: +}}|*6
|
{1:~{MATCH: +}}|*2
|
||||||
|
{2:]] .. fn.fnamemodify(cwd, ':~') .. pathsep .. [[Xfile [RO]{MATCH: +}}|
|
||||||
{MATCH: +}|
|
{MATCH: +}|
|
||||||
|
{1:~{MATCH: +}}|
|
||||||
|
{4:[No Name]{MATCH: +}}|
|
||||||
|
Allowed "]] .. cwd .. pathsep .. [[Xfile" in trust database.{MATCH: +}|
|
||||||
]])
|
]])
|
||||||
|
-- close the split for the next test below.
|
||||||
|
feed(':q<CR>')
|
||||||
|
|
||||||
local hash = fn.sha256(assert(read_file('Xfile')))
|
local hash = fn.sha256(assert(read_file('Xfile')))
|
||||||
trust = assert(read_file(stdpath('state') .. pathsep .. 'trust'))
|
trust = assert(read_file(stdpath('state') .. pathsep .. 'trust'))
|
||||||
@@ -114,7 +123,7 @@ describe('vim.secure', function()
|
|||||||
{2:{MATCH: +}}|
|
{2:{MATCH: +}}|
|
||||||
:lua vim.secure.read('Xfile'){MATCH: +}|
|
:lua vim.secure.read('Xfile'){MATCH: +}|
|
||||||
{3:]] .. msg .. [[}{MATCH: +}|
|
{3:]] .. msg .. [[}{MATCH: +}|
|
||||||
{3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}|
|
{3:[i]gnore, (v)iew, (d)eny: }^{MATCH: +}|
|
||||||
]])
|
]])
|
||||||
feed('i')
|
feed('i')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
@@ -133,7 +142,7 @@ describe('vim.secure', function()
|
|||||||
{2:{MATCH: +}}|
|
{2:{MATCH: +}}|
|
||||||
:lua vim.secure.read('Xfile'){MATCH: +}|
|
:lua vim.secure.read('Xfile'){MATCH: +}|
|
||||||
{3:]] .. msg .. [[}{MATCH: +}|
|
{3:]] .. msg .. [[}{MATCH: +}|
|
||||||
{3:[i]gnore, (v)iew, (d)eny, (a)llow: }^{MATCH: +}|
|
{3:[i]gnore, (v)iew, (d)eny: }^{MATCH: +}|
|
||||||
]])
|
]])
|
||||||
feed('v')
|
feed('v')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
|
Reference in New Issue
Block a user