fix: validate repository URI before source kind
This commit is contained in:
@@ -484,6 +484,18 @@ impl RuntimeGitMaterializer {
|
|||||||
Ok(binding)
|
Ok(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_plain_http_source(
|
||||||
|
request: &WorkingDirectoryRequest,
|
||||||
|
) -> Result<(), WorkingDirectoryDiagnostic> {
|
||||||
|
if url::Url::parse(&request.repository.source.uri).is_ok_and(|url| url.scheme() == "http") {
|
||||||
|
return Err(WorkingDirectoryDiagnostic::new(
|
||||||
|
"working_directory_repository_plain_http_unsupported",
|
||||||
|
"plain HTTP Repository sources are not executable; register an HTTPS or SSH source instead",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_request(
|
fn validate_request(
|
||||||
request: &WorkingDirectoryRequest,
|
request: &WorkingDirectoryRequest,
|
||||||
) -> Result<(), WorkingDirectoryDiagnostic> {
|
) -> Result<(), WorkingDirectoryDiagnostic> {
|
||||||
@@ -499,6 +511,7 @@ impl RuntimeGitMaterializer {
|
|||||||
"the configured Repository provider is unsupported",
|
"the configured Repository provider is unsupported",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Self::validate_plain_http_source(request)?;
|
||||||
if matches!(
|
if matches!(
|
||||||
request.repository.source.kind,
|
request.repository.source.kind,
|
||||||
workspace_api::RepositorySourceKind::Https | workspace_api::RepositorySourceKind::Ssh
|
workspace_api::RepositorySourceKind::Https | workspace_api::RepositorySourceKind::Ssh
|
||||||
@@ -540,20 +553,10 @@ impl RuntimeGitMaterializer {
|
|||||||
validate_ssh_materialization_access(ssh)?;
|
validate_ssh_materialization_access(ssh)?;
|
||||||
}
|
}
|
||||||
workspace_api::RepositorySourceKind::Invalid => {
|
workspace_api::RepositorySourceKind::Invalid => {
|
||||||
let is_plain_http = url::Url::parse(&request.repository.source.uri)
|
return Err(WorkingDirectoryDiagnostic::new(
|
||||||
.is_ok_and(|url| url.scheme() == "http");
|
|
||||||
let (code, message) = if is_plain_http {
|
|
||||||
(
|
|
||||||
"working_directory_repository_plain_http_unsupported",
|
|
||||||
"plain HTTP Repository sources are not executable; register an HTTPS or SSH source instead",
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
"working_directory_repository_source_invalid",
|
"working_directory_repository_source_invalid",
|
||||||
"configured Repository source is invalid and cannot be materialized",
|
"configured Repository source is invalid and cannot be materialized",
|
||||||
)
|
));
|
||||||
};
|
|
||||||
return Err(WorkingDirectoryDiagnostic::new(code, message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
validate_selector(request.repository.selector.as_deref().unwrap_or("HEAD"))
|
validate_selector(request.repository.selector.as_deref().unwrap_or("HEAD"))
|
||||||
@@ -627,6 +630,7 @@ impl RuntimeGitMaterializer {
|
|||||||
request: &WorkingDirectoryRequest,
|
request: &WorkingDirectoryRequest,
|
||||||
) -> Result<WorkingDirectoryBinding, WorkingDirectoryDiagnostic> {
|
) -> Result<WorkingDirectoryBinding, WorkingDirectoryDiagnostic> {
|
||||||
validate_working_directory_id(&working_directory_id)?;
|
validate_working_directory_id(&working_directory_id)?;
|
||||||
|
Self::validate_plain_http_source(request)?;
|
||||||
let request =
|
let request =
|
||||||
self.request_with_authorized_repository_access(&working_directory_id, request)?;
|
self.request_with_authorized_repository_access(&working_directory_id, request)?;
|
||||||
Self::validate_request(&request)?;
|
Self::validate_request(&request)?;
|
||||||
@@ -3812,6 +3816,34 @@ mod tests {
|
|||||||
"plain HTTP rejection must occur before invoking Git"
|
"plain HTTP rejection must occur before invoking Git"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for (offset, kind) in [
|
||||||
|
workspace_api::RepositorySourceKind::LocalPath,
|
||||||
|
workspace_api::RepositorySourceKind::File,
|
||||||
|
workspace_api::RepositorySourceKind::Https,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let mut mismatched_http = request(repo.path());
|
||||||
|
mismatched_http.repository.source = workspace_api::RepositorySource {
|
||||||
|
kind,
|
||||||
|
uri: "http://example.test/repo.git".to_string(),
|
||||||
|
};
|
||||||
|
let git_invocations_before = test_repository_git_invocation_count();
|
||||||
|
let error = materializer
|
||||||
|
.materialize(&worker_ref(4 + offset as u64), &mismatched_http)
|
||||||
|
.expect_err("plain HTTP URI must fail regardless of its declared source kind");
|
||||||
|
assert_eq!(
|
||||||
|
error.code,
|
||||||
|
"working_directory_repository_plain_http_unsupported"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
test_repository_git_invocation_count(),
|
||||||
|
git_invocations_before,
|
||||||
|
"mismatched plain HTTP source must fail before invoking Git"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let mut ssh = request(repo.path());
|
let mut ssh = request(repo.path());
|
||||||
ssh.repository.source = workspace_api::RepositorySource {
|
ssh.repository.source = workspace_api::RepositorySource {
|
||||||
kind: workspace_api::RepositorySourceKind::Ssh,
|
kind: workspace_api::RepositorySourceKind::Ssh,
|
||||||
|
|||||||
@@ -1980,6 +1980,17 @@ mod tests {
|
|||||||
let error = validate_repository_access_source("remote", &source).unwrap_err();
|
let error = validate_repository_access_source("remote", &source).unwrap_err();
|
||||||
assert!(error.to_string().contains("unsupported plain HTTP"));
|
assert!(error.to_string().contains("unsupported plain HTTP"));
|
||||||
assert!(error.to_string().contains("HTTPS or SSH"));
|
assert!(error.to_string().contains("HTTPS or SSH"));
|
||||||
|
|
||||||
|
let mismatched = workspace_api::RepositorySource {
|
||||||
|
kind: workspace_api::RepositorySourceKind::Https,
|
||||||
|
uri: "http://git.example.test/team/project.git".to_string(),
|
||||||
|
};
|
||||||
|
let error = validate_repository_access_source("remote", &mismatched).unwrap_err();
|
||||||
|
assert!(
|
||||||
|
error
|
||||||
|
.to_string()
|
||||||
|
.contains("repository_source_plain_http_unsupported")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -113,8 +113,7 @@ pub fn classify_legacy_repository_source(value: &str) -> RepositorySource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_plain_http_repository_source(source: &RepositorySource) -> bool {
|
pub(crate) fn is_plain_http_repository_source(source: &RepositorySource) -> bool {
|
||||||
source.kind == RepositorySourceKind::Invalid
|
Url::parse(&source.uri).is_ok_and(|url| url.scheme() == "http")
|
||||||
&& Url::parse(&source.uri).is_ok_and(|url| url.scheme() == "http")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repository_source_fingerprint(source: &RepositorySource) -> String {
|
pub fn repository_source_fingerprint(source: &RepositorySource) -> String {
|
||||||
|
|||||||
Reference in New Issue
Block a user