Repository navigation
fix(idris-dependents): green CI on main + close #628 review findings #644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
09168da
f7a9366
5708183
f6c3675
9eccde1
a4fabd3
50a5b5f
7d840d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,32 +11,74 @@ pub struct PackRef { | |
| pub url: String, | ||
| } | ||
|
|
||
| /// Match a watched owner in a GitHub-style repository reference, including | ||
| /// HTTPS, SSH, and scp forms. Owner matching is ASCII case-insensitive and | ||
| /// requires a following `/`. | ||
| /// | ||
| /// This is a textual check, not full URL validation: `github.com` may follow | ||
| /// `/`, `@`, or `.` (or start the input), so subdomains and embedded paths can match. | ||
| pub fn points_at(url: &str, owners: &[String]) -> bool { | ||
| let url = url.to_ascii_lowercase(); | ||
| let mut from = 0; | ||
| while let Some(k) = url[from..].find("github.com") { | ||
| let at = from + k; | ||
| let host_start = at == 0 || matches!(url.as_bytes()[at - 1], b'/' | b'@' | b'.'); | ||
| let rest = &url[at + "github.com".len()..]; | ||
| if host_start && (rest.starts_with('/') || rest.starts_with(':')) { | ||
| let path = &rest[1..]; | ||
| if owners.iter().any(|o| { | ||
| let o = o.to_ascii_lowercase(); | ||
| path.strip_prefix(o.as_str()) | ||
| .is_some_and(|r| r.starts_with('/')) | ||
| }) { | ||
| return true; | ||
| /// The repository path of a GitHub URL (`scheme://[user@]host[:port]/path` or | ||
| /// scp-style `[user@]host:path`), lower-cased, when the host is GitHub itself. | ||
| fn github_path(url: &str) -> Option<String> { | ||
| let url = url.trim().to_ascii_lowercase(); | ||
| let (authority, path) = match url.find("://") { | ||
| Some(i) => { | ||
| let rest = &url[i + 3..]; | ||
| // The authority ends at the first `/`, `?` or `#` (RFC 3986), so | ||
| // `https://evil.example#@github.com/...` has host `evil.example`. | ||
| let end = rest.find(['/', '?', '#'])?; | ||
| if !rest[end..].starts_with('/') { | ||
| return None; | ||
| } | ||
| (&rest[..end], &rest[end + 1..]) | ||
| } | ||
|
hyperpolymath marked this conversation as resolved.
Resolved
|
||
| None => { | ||
| let colon = url.find(':')?; | ||
| if url[..colon].contains('/') { | ||
| return None; | ||
| } | ||
| (&url[..colon], url[colon + 1..].trim_start_matches('/')) | ||
| } | ||
| }; | ||
| let host = authority.rsplit('@').next()?.split(':').next()?; | ||
| matches!(host, "github.com" | "www.github.com").then(|| path.to_string()) | ||
|
Comment on lines
+37
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For a value such as Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| /// Match a watched owner in a GitHub repository URL (HTTPS, SSH or scp form). | ||
| /// GitHub must be the URL's host, not merely appear in its path, and the owner | ||
| /// must be followed by a repository name. Matching is ASCII case-insensitive. | ||
| pub fn points_at(url: &str, owners: &[String]) -> bool { | ||
| github_path(url).is_some_and(|path| { | ||
| // A query or fragment is not part of the repository path. | ||
| let path = path.split(['?', '#']).next().unwrap_or(""); | ||
| let mut parts = path.split('/'); | ||
| let (Some(owner), Some(repo)) = (parts.next(), parts.next()) else { | ||
| return false; | ||
| }; | ||
| !repo.is_empty() && owners.iter().any(|o| o.eq_ignore_ascii_case(owner)) | ||
|
hyperpolymath marked this conversation as resolved.
Resolved
|
||
| }) | ||
| } | ||
|
|
||
| /// Resolve a submodule URL relative to its superproject (`../x` and `./x`, as | ||
| /// git does against the superproject's remote), taking the remote to be | ||
| /// `https://github.com/<full_name>`. Absolute URLs are returned unchanged. | ||
| /// Like git, `../` may climb past `owner/repo` into the host part, so | ||
| /// `../../../github.com/o/r` from `a/b` is `https://github.com/o/r`; climbing | ||
| /// past the host yields `None` (git's result there is never a GitHub URL). | ||
| fn resolve_submodule_url(url: &str, superproject: Option<&str>) -> Option<String> { | ||
| if !(url.starts_with("../") || url.starts_with("./")) { | ||
| return Some(url.to_string()); | ||
| } | ||
| let mut base: Vec<&str> = std::iter::once("github.com") | ||
| .chain(superproject?.split('/').filter(|s| !s.is_empty())) | ||
| .collect(); | ||
| let mut rest = url; | ||
| loop { | ||
| if let Some(r) = rest.strip_prefix("../") { | ||
| base.pop()?; | ||
|
hyperpolymath marked this conversation as resolved.
Resolved
|
||
| rest = r; | ||
| } else if let Some(r) = rest.strip_prefix("./") { | ||
| rest = r; | ||
| } else { | ||
| break; | ||
| } | ||
| from = at + 1; | ||
| } | ||
| false | ||
| base.push(rest); | ||
| Some(format!("https://{}", base.join("/"))) | ||
|
Comment on lines
+80
to
+81
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
With Git 2.43 and a superproject remote of Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| /// `pack.toml` custom entries pointing at `owners`, in file order. | ||
|
|
@@ -68,20 +110,35 @@ pub fn pack_toml_refs(text: &str, owners: &[String]) -> Result<Vec<PackRef>, tom | |
| /// Extract URLs matching `owners` from trimmed `url =` lines, in input order. | ||
| /// Double-quoted values end at the next quote; unquoted values end at `#` or | ||
| /// `;`. Sections and escapes are not interpreted, and duplicates are retained. | ||
| /// Relative URLs cannot be resolved without the superproject, so they are | ||
| /// skipped; see [`gitmodules_refs_in`]. | ||
| pub fn gitmodules_refs(text: &str, owners: &[String]) -> Vec<String> { | ||
| gitmodules_refs_in(text, owners, None) | ||
| } | ||
|
|
||
| /// Like [`gitmodules_refs`], resolving relative submodule URLs against the | ||
| /// GitHub repository `superproject` (`owner/repo`). Keys are matched | ||
| /// case-insensitively, as git config does; relative matches are returned | ||
| /// resolved to absolute URLs. | ||
| pub fn gitmodules_refs_in( | ||
| text: &str, | ||
| owners: &[String], | ||
| superproject: Option<&str>, | ||
| ) -> Vec<String> { | ||
| text.lines() | ||
| .filter_map(|line| { | ||
| let line = line.trim(); | ||
| let value = line | ||
| .strip_prefix("url")? | ||
| .trim_start() | ||
| .strip_prefix('=')? | ||
| .trim(); | ||
| let key = line.get(..3)?; | ||
| if !key.eq_ignore_ascii_case("url") { | ||
| return None; | ||
| } | ||
| let value = line[3..].trim_start().strip_prefix('=')?.trim(); | ||
| let value = match value.strip_prefix('"') { | ||
| Some(q) => q.split('"').next().unwrap_or(""), | ||
| None => value.split(['#', ';']).next().unwrap_or("").trim(), | ||
| }; | ||
| points_at(value, owners).then(|| value.to_string()) | ||
| let url = resolve_submodule_url(value, superproject)?; | ||
| points_at(&url, owners).then_some(url) | ||
| }) | ||
| .collect() | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: hyperpolymath/gitbot-fleet
Length of output: 8651
Script executed:
Repository: hyperpolymath/gitbot-fleet
Length of output: 10638
Script executed:
Repository: hyperpolymath/gitbot-fleet
Length of output: 12551
Validate the scheme before parsing the authority.
The exact
https://evil.example/...example is rejected, but a scheme-less value such asevil.example/?next=://github.com/hyperpolymath/provenis accepted.pack.tomland.gitmodulesvalues reachpoints_atwithout earlier scheme validation. This false reference can produceConfidence::Highbecause any pack or submodule reference receives high confidence.Suggested fix
Committable suggestion