mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
hooks: forbid windows reserved names in the repos
Summary: The root cause for S199754 was a file named "con.rs" was checked in onto the repo. Since this is a reserved filename on Windows, this broke all Windows users having it in their sparse profiles. The rules for reserved names are defined as such by Microsoft: "CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended. For more information, see Namespaces." Of course, since the filesystem is case insensitive, these can have any casing. Reviewed By: krallin Differential Revision: D24453528 fbshipit-source-id: 389f15e2b1a88e3c1e8721fb7868616acabebc64
This commit is contained in:
parent
62e5d16d62
commit
c5480fdf6f
@ -20,6 +20,7 @@ mod lua_pattern;
|
||||
pub(crate) mod no_bad_filenames;
|
||||
mod no_insecure_filenames;
|
||||
pub(crate) mod no_questionable_filenames;
|
||||
pub(crate) mod no_windows_filenames;
|
||||
|
||||
use anyhow::Result;
|
||||
use fbinit::FacebookInit;
|
||||
@ -91,6 +92,11 @@ pub fn hook_name_to_file_hook(
|
||||
.set_from_config(config)
|
||||
.build()?,
|
||||
)),
|
||||
"no_windows_filenames" => Some(Box::new(
|
||||
no_windows_filenames::NoWindowsFilenames::builder()
|
||||
.set_from_config(config)
|
||||
.build()?,
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
103
eden/mononoke/hooks/src/rust_hooks/no_windows_filenames.rs
Normal file
103
eden/mononoke/hooks/src/rust_hooks/no_windows_filenames.rs
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
use crate::{CrossRepoPushSource, FileContentFetcher, FileHook, HookExecution, HookRejectionInfo};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use context::CoreContext;
|
||||
use metaconfig_types::HookConfig;
|
||||
use mononoke_types::{FileChange, MPath};
|
||||
use regex::bytes::Regex;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NoWindowsFilenamesBuilder<'a> {
|
||||
/// Paths on which bad Windows filenames are not disallowed.
|
||||
allowed_paths: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> NoWindowsFilenamesBuilder<'a> {
|
||||
pub fn set_from_config(mut self, config: &'a HookConfig) -> Self {
|
||||
if let Some(v) = config.strings.get("allowed_paths") {
|
||||
self = self.allowed_paths(v)
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn allowed_paths(mut self, regex: &'a str) -> Self {
|
||||
self.allowed_paths = Some(regex);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<NoWindowsFilenames> {
|
||||
Ok(NoWindowsFilenames {
|
||||
allowed_paths: self
|
||||
.allowed_paths
|
||||
.map(Regex::new)
|
||||
.transpose()
|
||||
.context("Failed to create allowed_paths regex")?,
|
||||
bad_windows_path_element: Regex::new(r"^(?i)(((com|lpt)\d$)|(con|prn|aux|nul))($|\.)")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NoWindowsFilenames {
|
||||
allowed_paths: Option<Regex>,
|
||||
bad_windows_path_element: Regex,
|
||||
}
|
||||
|
||||
/// Hook to disallow bad Windows filenames from being pushed.
|
||||
///
|
||||
/// These bad filenames are described by Microsoft as:
|
||||
/// "CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3,
|
||||
/// LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an
|
||||
/// extension; for example, NUL.txt is not recommended. For more information, see Namespaces."
|
||||
impl NoWindowsFilenames {
|
||||
pub fn builder<'a>() -> NoWindowsFilenamesBuilder<'a> {
|
||||
NoWindowsFilenamesBuilder::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl FileHook for NoWindowsFilenames {
|
||||
async fn run<'this: 'change, 'ctx: 'this, 'change, 'fetcher: 'change, 'path: 'change>(
|
||||
&'this self,
|
||||
_ctx: &'ctx CoreContext,
|
||||
_context_fetcher: &'fetcher dyn FileContentFetcher,
|
||||
change: Option<&'change FileChange>,
|
||||
path: &'path MPath,
|
||||
cross_repo_push_source: CrossRepoPushSource,
|
||||
) -> Result<HookExecution> {
|
||||
if cross_repo_push_source == CrossRepoPushSource::PushRedirected {
|
||||
// For push-redirected pushes we rely on the hook
|
||||
// running in the original repo
|
||||
return Ok(HookExecution::Accepted);
|
||||
}
|
||||
|
||||
if change.is_none() {
|
||||
return Ok(HookExecution::Accepted);
|
||||
}
|
||||
|
||||
if let Some(allowed_paths) = &self.allowed_paths {
|
||||
if allowed_paths.is_match(&path.to_vec()) {
|
||||
return Ok(HookExecution::Accepted);
|
||||
}
|
||||
}
|
||||
|
||||
for element in path {
|
||||
if self.bad_windows_path_element.is_match(element.as_ref()) {
|
||||
return Ok(HookExecution::Rejected(HookRejectionInfo::new_long(
|
||||
"Illegal windows filename",
|
||||
format!("ABORT: Illegal windows filename: {}", element),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(HookExecution::Accepted)
|
||||
}
|
||||
}
|
136
eden/mononoke/tests/integration/test-hook-no-windows-filenames.t
Normal file
136
eden/mononoke/tests/integration/test-hook-no-windows-filenames.t
Normal file
@ -0,0 +1,136 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
#
|
||||
# This software may be used and distributed according to the terms of the
|
||||
# GNU General Public License found in the LICENSE file in the root
|
||||
# directory of this source tree.
|
||||
|
||||
$ . "${TEST_FIXTURES}/library.sh"
|
||||
$ export LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8
|
||||
|
||||
$ hook_test_setup no_windows_filenames <( \
|
||||
> echo 'bypass_pushvar="ALLOW_BAD_WINDOWS_FILENAMES=true"'
|
||||
> )
|
||||
|
||||
$ hg up -q 0
|
||||
$ echo "ok" > "com"
|
||||
$ hg ci -Aqm success
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 2bdf0e02c487 to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 0 changes to 0 files
|
||||
updating bookmark master_bookmark
|
||||
|
||||
$ hg up -q 0
|
||||
$ echo "bad" > "COM5"
|
||||
$ hg ci -Aqm failure
|
||||
warning: filename contains 'COM5', which is reserved on Windows: COM5
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 0a31cb8056d1 to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
remote: Command failed
|
||||
remote: Error:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 0a31cb8056d10d69d6652e754aeee9ecdd5f9e7b: ABORT: Illegal windows filename: COM5
|
||||
remote:
|
||||
remote: Root cause:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 0a31cb8056d10d69d6652e754aeee9ecdd5f9e7b: ABORT: Illegal windows filename: COM5
|
||||
remote:
|
||||
remote: Debug context:
|
||||
remote: "hooks failed:\nno_windows_filenames for 0a31cb8056d10d69d6652e754aeee9ecdd5f9e7b: ABORT: Illegal windows filename: COM5"
|
||||
abort: stream ended unexpectedly (got 0 bytes, expected 4)
|
||||
[255]
|
||||
|
||||
$ hg up -q 0
|
||||
$ echo "bad" > "nul.txt"
|
||||
$ hg ci -Aqm failure
|
||||
warning: filename contains 'nul', which is reserved on Windows: nul.txt
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 7e7f8fb54a0b to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
remote: Command failed
|
||||
remote: Error:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 7e7f8fb54a0b8f692fbf224a33476b864f11dfe9: ABORT: Illegal windows filename: nul.txt
|
||||
remote:
|
||||
remote: Root cause:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 7e7f8fb54a0b8f692fbf224a33476b864f11dfe9: ABORT: Illegal windows filename: nul.txt
|
||||
remote:
|
||||
remote: Debug context:
|
||||
remote: "hooks failed:\nno_windows_filenames for 7e7f8fb54a0b8f692fbf224a33476b864f11dfe9: ABORT: Illegal windows filename: nul.txt"
|
||||
abort: stream ended unexpectedly (got 0 bytes, expected 4)
|
||||
[255]
|
||||
|
||||
$ hg up -q 0
|
||||
$ mkdir dir
|
||||
$ echo "bad" > dir/CoN.txt
|
||||
$ hg ci -Aqm failure
|
||||
warning: filename contains 'CoN', which is reserved on Windows: dir/CoN.txt
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 49604693a23c to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
remote: Command failed
|
||||
remote: Error:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 49604693a23c85a9ee0f6036d330b535842610dc: ABORT: Illegal windows filename: CoN.txt
|
||||
remote:
|
||||
remote: Root cause:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 49604693a23c85a9ee0f6036d330b535842610dc: ABORT: Illegal windows filename: CoN.txt
|
||||
remote:
|
||||
remote: Debug context:
|
||||
remote: "hooks failed:\nno_windows_filenames for 49604693a23c85a9ee0f6036d330b535842610dc: ABORT: Illegal windows filename: CoN.txt"
|
||||
abort: stream ended unexpectedly (got 0 bytes, expected 4)
|
||||
[255]
|
||||
|
||||
$ hg up -q 0
|
||||
$ mkdir dir
|
||||
$ echo "ok" > dir/Icon.txt
|
||||
$ hg ci -Aqm success
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 74f01fef9e70 to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 0 changes to 0 files
|
||||
updating bookmark master_bookmark
|
||||
|
||||
$ hg up -q 0
|
||||
$ mkdir dir
|
||||
$ echo "ok" > dir/Icom5
|
||||
$ hg ci -Aqm success
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 47222c857e63 to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
adding changesets
|
||||
adding manifests
|
||||
adding file changes
|
||||
added 1 changesets with 0 changes to 0 files
|
||||
updating bookmark master_bookmark
|
||||
|
||||
$ hg up -q 0
|
||||
$ mkdir con
|
||||
$ echo "bad" > con/foo
|
||||
$ hg ci -Aqm failure
|
||||
warning: filename contains 'con', which is reserved on Windows: con/foo
|
||||
$ hgmn push -r . --to master_bookmark
|
||||
pushing rev 115c8cee8249 to destination ssh://user@dummy/repo bookmark master_bookmark
|
||||
searching for changes
|
||||
remote: Command failed
|
||||
remote: Error:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 115c8cee824903baec5607a5b5d731f4a92e5859: ABORT: Illegal windows filename: con
|
||||
remote:
|
||||
remote: Root cause:
|
||||
remote: hooks failed:
|
||||
remote: no_windows_filenames for 115c8cee824903baec5607a5b5d731f4a92e5859: ABORT: Illegal windows filename: con
|
||||
remote:
|
||||
remote: Debug context:
|
||||
remote: "hooks failed:\nno_windows_filenames for 115c8cee824903baec5607a5b5d731f4a92e5859: ABORT: Illegal windows filename: con"
|
||||
abort: stream ended unexpectedly (got 0 bytes, expected 4)
|
||||
[255]
|
Loading…
Reference in New Issue
Block a user