mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat(registry): support granular allowence of specifier types
This commit is contained in:
parent
36e6f16ca6
commit
16ab05ec72
4 changed files with 79 additions and 57 deletions
|
@ -19,10 +19,10 @@ To create an index, create a new repository and add a `config.toml` file with
|
||||||
the following content:
|
the following content:
|
||||||
|
|
||||||
```toml title="config.toml"
|
```toml title="config.toml"
|
||||||
# The URL of the registry API
|
# the URL of the registry API
|
||||||
api = "https://registry.acme.local/"
|
api = "https://registry.acme.local/"
|
||||||
|
|
||||||
# Package download URL (optional)
|
# package download URL (optional)
|
||||||
download = "{API_URL}/v0/packages/{PACKAGE}/{PACKAGE_VERSION}/{PACKAGE_TARGET}"
|
download = "{API_URL}/v0/packages/{PACKAGE}/{PACKAGE_VERSION}/{PACKAGE_TARGET}"
|
||||||
|
|
||||||
# the client ID of the GitHub OAuth app (optional)
|
# the client ID of the GitHub OAuth app (optional)
|
||||||
|
@ -33,13 +33,16 @@ git_allowed = true
|
||||||
|
|
||||||
# whether to allow packages which depend on packages from other registries
|
# whether to allow packages which depend on packages from other registries
|
||||||
# (default: false)
|
# (default: false)
|
||||||
other_registries_allowed = true
|
other_registries_allowed = ["https://git.acme.local/index"]
|
||||||
|
|
||||||
# whether to allow packages with Wally dependencies (default: false)
|
# whether to allow packages with Wally dependencies (default: false)
|
||||||
wally_allowed = false
|
wally_allowed = false
|
||||||
|
|
||||||
# the maximum size of the archive in bytes (default: 4MB)
|
# the maximum size of the archive in bytes (default: 4MB)
|
||||||
max_archive_size = 4194304
|
max_archive_size = 4194304
|
||||||
|
|
||||||
|
# the scripts packages present in the `init` command selection by default
|
||||||
|
scripts_packages = ["pesde/scripts_rojo"]
|
||||||
```
|
```
|
||||||
|
|
||||||
- **api**: The URL of the registry API. See below for more information.
|
- **api**: The URL of the registry API. See below for more information.
|
||||||
|
@ -60,18 +63,24 @@ max_archive_size = 4194304
|
||||||
- **github_oauth_client_id**: This is required if you use GitHub OAuth for
|
- **github_oauth_client_id**: This is required if you use GitHub OAuth for
|
||||||
authentication. See below for more information.
|
authentication. See below for more information.
|
||||||
|
|
||||||
- **git_allowed**: Whether to allow packages with Git dependencies. This is
|
- **git_allowed**: Whether to allow packages with Git dependencies. This can be
|
||||||
optional and defaults to `false`.
|
either a bool or a list of allowed repository URLs. This is optional and
|
||||||
|
defaults to `false`.
|
||||||
|
|
||||||
- **other_registries_allowed**: Whether to allow packages which depend on
|
- **other_registries_allowed**: Whether to allow packages which depend on
|
||||||
packages from other registries. This is optional and defaults to `false`.
|
packages from other registries. This can be either a bool or a list of
|
||||||
|
allowed index repository URLs. This is optional and defaults to `false`.
|
||||||
|
|
||||||
- **wally_allowed**: Whether to allow packages with Wally dependencies. This is
|
- **wally_allowed**: Whether to allow packages with Wally dependencies. This can
|
||||||
|
be either a bool or a list of allowed index repository URLs. This is
|
||||||
optional and defaults to `false`.
|
optional and defaults to `false`.
|
||||||
|
|
||||||
- **max_archive_size**: The maximum size of the archive in bytes. This is
|
- **max_archive_size**: The maximum size of the archive in bytes. This is
|
||||||
optional and defaults to `4194304` (4MB).
|
optional and defaults to `4194304` (4MB).
|
||||||
|
|
||||||
|
- **scripts_packages**: The scripts packages present in the `init` command
|
||||||
|
selection by default. This is optional and defaults to none.
|
||||||
|
|
||||||
You should then push this repository to [GitHub](https://github.com/).
|
You should then push this repository to [GitHub](https://github.com/).
|
||||||
|
|
||||||
## Configuring the registry
|
## Configuring the registry
|
||||||
|
@ -88,8 +97,8 @@ has access to the index repository. We recommend using a separate account
|
||||||
for this purpose.
|
for this purpose.
|
||||||
|
|
||||||
<Aside>
|
<Aside>
|
||||||
For a GitHub account the password **must** be a personal access token. For
|
For a GitHub account the password **must** be a personal access token. For instructions on how to
|
||||||
instructions on how to create a personal access token, see the [GitHub
|
create a personal access token, see the [GitHub
|
||||||
documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).
|
documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).
|
||||||
The access token must have read and write access to the index repository.
|
The access token must have read and write access to the index repository.
|
||||||
</Aside>
|
</Aside>
|
||||||
|
|
|
@ -304,7 +304,7 @@ pub async fn publish_package(
|
||||||
.filter(|index| match gix::Url::try_from(*index) {
|
.filter(|index| match gix::Url::try_from(*index) {
|
||||||
Ok(url) => config
|
Ok(url) => config
|
||||||
.other_registries_allowed
|
.other_registries_allowed
|
||||||
.is_allowed(source.repo_url().clone(), url),
|
.is_allowed_or_same(source.repo_url().clone(), url),
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
})
|
})
|
||||||
.is_none()
|
.is_none()
|
||||||
|
@ -315,16 +315,13 @@ pub async fn publish_package(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Wally(specifier) => {
|
DependencySpecifiers::Wally(specifier) => {
|
||||||
if !config.wally_allowed {
|
|
||||||
return Err(Error::InvalidArchive(
|
|
||||||
"wally dependencies are not allowed".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if specifier
|
if specifier
|
||||||
.index
|
.index
|
||||||
.as_ref()
|
.as_deref()
|
||||||
.filter(|index| index.parse::<url::Url>().is_ok())
|
.filter(|index| match gix::Url::try_from(*index) {
|
||||||
|
Ok(url) => config.wally_allowed.is_allowed(url),
|
||||||
|
Err(_) => false,
|
||||||
|
})
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
return Err(Error::InvalidArchive(format!(
|
return Err(Error::InvalidArchive(format!(
|
||||||
|
@ -332,15 +329,15 @@ pub async fn publish_package(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Git(_) => {
|
DependencySpecifiers::Git(specifier) => {
|
||||||
if !config.git_allowed {
|
if !config.git_allowed.is_allowed(specifier.repo.clone()) {
|
||||||
return Err(Error::InvalidArchive(
|
return Err(Error::InvalidArchive(
|
||||||
"git dependencies are not allowed".into(),
|
"git dependencies are not allowed".into(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Workspace(_) => {
|
DependencySpecifiers::Workspace(_) => {
|
||||||
// workspace specifiers are to be transformed into Pesde specifiers by the sender
|
// workspace specifiers are to be transformed into pesde specifiers by the sender
|
||||||
return Err(Error::InvalidArchive(
|
return Err(Error::InvalidArchive(
|
||||||
"non-transformed workspace dependency".into(),
|
"non-transformed workspace dependency".into(),
|
||||||
));
|
));
|
||||||
|
|
|
@ -9,6 +9,7 @@ use pesde::{
|
||||||
matching_globs_old_behaviour,
|
matching_globs_old_behaviour,
|
||||||
scripts::ScriptName,
|
scripts::ScriptName,
|
||||||
source::{
|
source::{
|
||||||
|
git_index::GitBasedSource,
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::PackageSource,
|
traits::PackageSource,
|
||||||
|
@ -362,10 +363,6 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wally-compat")]
|
|
||||||
let mut has_wally = false;
|
|
||||||
let mut has_git = false;
|
|
||||||
|
|
||||||
for specifier in manifest
|
for specifier in manifest
|
||||||
.dependencies
|
.dependencies
|
||||||
.values_mut()
|
.values_mut()
|
||||||
|
@ -389,8 +386,6 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
}
|
}
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
DependencySpecifiers::Wally(specifier) => {
|
DependencySpecifiers::Wally(specifier) => {
|
||||||
has_wally = true;
|
|
||||||
|
|
||||||
let index_name = specifier
|
let index_name = specifier
|
||||||
.index
|
.index
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
@ -406,9 +401,7 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Git(_) => {
|
DependencySpecifiers::Git(_) => {}
|
||||||
has_git = true;
|
|
||||||
}
|
|
||||||
DependencySpecifiers::Workspace(spec) => {
|
DependencySpecifiers::Workspace(spec) => {
|
||||||
let pkg_ref = WorkspacePackageSource
|
let pkg_ref = WorkspacePackageSource
|
||||||
.resolve(spec, project, target_kind, &mut HashSet::new())
|
.resolve(spec, project, target_kind, &mut HashSet::new())
|
||||||
|
@ -570,8 +563,7 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
.get(&self.index)
|
.get(&self.index)
|
||||||
.context(format!("missing index {}", self.index))?;
|
.context(format!("missing index {}", self.index))?;
|
||||||
let source = PesdePackageSource::new(index_url.clone());
|
let source = PesdePackageSource::new(index_url.clone());
|
||||||
source
|
PackageSource::refresh(&source, project)
|
||||||
.refresh(project)
|
|
||||||
.await
|
.await
|
||||||
.context("failed to refresh source")?;
|
.context("failed to refresh source")?;
|
||||||
let config = source
|
let config = source
|
||||||
|
@ -587,15 +579,31 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest.all_dependencies().context("dependency conflict")?;
|
let deps = manifest.all_dependencies().context("dependency conflict")?;
|
||||||
|
|
||||||
if !config.git_allowed && has_git {
|
if let Some((disallowed, _)) = deps.iter().find(|(_, (spec, _))| match spec {
|
||||||
anyhow::bail!("git dependencies are not allowed on this index");
|
DependencySpecifiers::Pesde(spec) => {
|
||||||
|
!config.other_registries_allowed.is_allowed_or_same(
|
||||||
|
source.repo_url().clone(),
|
||||||
|
manifest
|
||||||
|
.indices
|
||||||
|
.get(spec.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
||||||
|
.unwrap()
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
DependencySpecifiers::Git(spec) => !config.git_allowed.is_allowed(spec.repo.clone()),
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
if !config.wally_allowed && has_wally {
|
DependencySpecifiers::Wally(spec) => !config.wally_allowed.is_allowed(
|
||||||
anyhow::bail!("wally dependencies are not allowed on this index");
|
manifest
|
||||||
|
.wally_indices
|
||||||
|
.get(spec.index.as_deref().unwrap_or(DEFAULT_INDEX_NAME))
|
||||||
|
.unwrap()
|
||||||
|
.clone(),
|
||||||
|
),
|
||||||
|
_ => false,
|
||||||
|
}) {
|
||||||
|
anyhow::bail!("dependency `{disallowed}` is not allowed on this index");
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.dry_run {
|
if self.dry_run {
|
||||||
|
|
|
@ -274,22 +274,30 @@ impl Default for AllowedRegistries {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AllowedRegistries {
|
// strips .git suffix to allow for more flexible matching
|
||||||
/// Whether the given URL is allowed
|
fn simplify_url(mut url: Url) -> Url {
|
||||||
pub fn is_allowed(&self, mut this: Url, mut external: Url) -> bool {
|
url.path = url.path.strip_suffix(b".git").unwrap_or(&url.path).into();
|
||||||
// strip .git suffix to allow for more flexible matching
|
url
|
||||||
this.path = this.path.strip_suffix(b".git").unwrap_or(&this.path).into();
|
}
|
||||||
external.path = external
|
|
||||||
.path
|
|
||||||
.strip_suffix(b".git")
|
|
||||||
.unwrap_or(&external.path)
|
|
||||||
.into();
|
|
||||||
|
|
||||||
this == external
|
impl AllowedRegistries {
|
||||||
|| (match self {
|
fn _is_allowed(&self, url: &Url) -> bool {
|
||||||
|
match self {
|
||||||
Self::All(all) => *all,
|
Self::All(all) => *all,
|
||||||
Self::Specific(urls) => urls.contains(&this) || urls.contains(&external),
|
Self::Specific(urls) => urls.contains(url),
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the given URL is allowed
|
||||||
|
pub fn is_allowed(&self, url: Url) -> bool {
|
||||||
|
self._is_allowed(&simplify_url(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the given URL is allowed, or is the same as the given URL
|
||||||
|
pub fn is_allowed_or_same(&self, this: Url, external: Url) -> bool {
|
||||||
|
let this = simplify_url(this);
|
||||||
|
let external = simplify_url(external);
|
||||||
|
(this == external) || self._is_allowed(&external) || self._is_allowed(&this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,13 +310,13 @@ pub struct IndexConfig {
|
||||||
pub download: Option<String>,
|
pub download: Option<String>,
|
||||||
/// Whether Git is allowed as a source for publishing packages
|
/// Whether Git is allowed as a source for publishing packages
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub git_allowed: bool,
|
pub git_allowed: AllowedRegistries,
|
||||||
/// Whether other registries are allowed as a source for publishing packages
|
/// Whether other registries are allowed as a source for publishing packages
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub other_registries_allowed: AllowedRegistries,
|
pub other_registries_allowed: AllowedRegistries,
|
||||||
/// Whether Wally is allowed as a source for publishing packages
|
/// Whether Wally is allowed as a source for publishing packages
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wally_allowed: bool,
|
pub wally_allowed: AllowedRegistries,
|
||||||
/// The OAuth client ID for GitHub
|
/// The OAuth client ID for GitHub
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub github_oauth_client_id: Option<String>,
|
pub github_oauth_client_id: Option<String>,
|
||||||
|
|
Loading…
Reference in a new issue