Skip to content

Commit

Permalink
feat: setting to override trusted sites list (#1819)
Browse files Browse the repository at this point in the history
* Make trusted sites list configurable

* Fix Windows test failures

* Update user-changes.md

* Review
  • Loading branch information
Seb-MCaw authored Jan 13, 2025
1 parent 951bfec commit 09b3893
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
url = https://github.com/alire-project/simple_logging.git
[submodule "deps/ada-toml"]
path = deps/ada-toml
url = https://github.com/mosteo/ada-toml
url = https://github.com/pmderodat/ada-toml
[submodule "deps/gnatcoll-slim"]
path = deps/gnatcoll-slim
url = https://github.com/alire-project/gnatcoll-core.git
Expand Down
7 changes: 4 additions & 3 deletions alire.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ executables = ["alr"]

[[depends-on]]
aaa = "~0.3.0"
ada_toml = "~0.3"
ada_toml = "~0.5"
ajunitgen = "^1.0.1"
ansiada = "^1.1"
c_strings = "^1.0"
Expand Down Expand Up @@ -56,8 +56,9 @@ url = "https://github.com/mosteo/aaa"
commit = "ddfeffe2d6c8f9d19161df7b31d16d37bef4ba71"

[pins.ada_toml]
url = "https://github.com/mosteo/ada-toml"
commit = "da4e59c382ceb0de6733d571ecbab7ea4919b33d"
url = "https://github.com/pmderodat/ada-toml"
commit = "e760110ad2b5b776a44dace31b8421532e429fbb"

[pins.ansiada]
url = "https://github.com/mosteo/ansi-ada"
commit = "0772e48d3e1f640829d142745a36b37edcd5470b"
Expand Down
4 changes: 3 additions & 1 deletion doc/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,9 @@ where the `--for-private-index` switch disables the submission step and certain
checks which are only applicable to the community index, and the remaining
arguments function as described above. This will generate a manifest file which
you can place at the indicated path (relative to the location of `index.toml`)
in your private index.
in your private index. If you are using a remote Git repository which is not on
one of the community index's trusted hosts, you will need to configure it with
the `origins.git.trusted_sites` [setting](settings).

One important thing to note is that publishing from a local repository will
detect the URL configured as the Git remote (as displayed by
Expand Down
10 changes: 10 additions & 0 deletions doc/user-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ stay on top of `alr` new features.

## Release `2.1`

### Configurable trusted sites list for Git repositories

PR [#1819](https://github.com/alire-project/alire/pull/1819)

The list of hosts which the `alr publish --for-private-index` and
`alr index --check` commands consider to be trusted for Git repository origins
can now be configured with the `origins.git.trusted_sites` settings key. The
existing hard-coded list still applies when using `alr publish` to submit to the
community index.

### Custom download command for archive crates

PR [#1815](https://github.com/alire-project/alire/pull/1815)
Expand Down
4 changes: 3 additions & 1 deletion src/alire/alire-index.adb
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ package body Alire.Index is
for Crate of All_Crates.all loop
for Rel of Crate.Releases loop
if Rel.Origin.Kind in Origins.VCS_Kinds then
if not Publish.Is_Trusted (Rel.Origin.URL) then
if not Publish.Is_Trusted
(Rel.Origin.URL, For_Community => False)
then
OK := False;
Put_Warning ("Release " & Rel.Milestone.TTY_Image
& " has URL not in known hosts: "
Expand Down
72 changes: 53 additions & 19 deletions src/alire/alire-publish.adb
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,6 @@ package body Alire.Publish is
use Directories.Operators;
use AAA.Strings;

Trusted_Sites : constant AAA.Strings.Vector :=
AAA.Strings.Empty_Vector
.Append ("bitbucket.org")
.Append ("github.com")
.Append ("gitlab.com")
.Append ("savannah.gnu.org")
.Append ("savannah.nongnu.org")
.Append ("sf.net");

Early_Stop : exception;
-- Raise this exception from a step to terminate prematurely but without
-- generating an error. E.g., if the user doesn't want to submit online
Expand Down Expand Up @@ -939,13 +930,14 @@ package body Alire.Publish is

if Context.Origin.Kind in Origins.VCS_Kinds then

-- Check an VCS origin is from a trusted site, unless we are forcing
-- a local repository.
-- Check a VCS origin is from a trusted site, unless we are forcing
-- a local repository or '--for-private-index' is specified.

if (Force and then
URI.URI_Kind (URL) in URI.Local_URIs)
or else
Is_Trusted (URL)
Is_Trusted
(URL, For_Community => not Context.Options.For_Private_Index)
then
Put_Success ("Origin is hosted on trusted site: "
& URI.Host (URL));
Expand Down Expand Up @@ -1084,13 +1076,50 @@ package body Alire.Publish is
else No_Steps));
end Directory_Tar;

-------------------
-- Trusted_Sites --
-------------------

function Trusted_Sites (For_Community : Boolean) return Vector is
Space_Separated : constant String :=
(if For_Community then Community_Trusted_Sites
else Settings.Builtins.Origins_Git_Trusted_Sites.Get);
Split_Vector : constant Vector := Split (Space_Separated, ' ');
Sites : Vector := Empty_Vector;
begin
for Site of Split_Vector loop
if Site /= "" then
Sites.Append (Site);
end if;
end loop;
return Sites;
end Trusted_Sites;

---------------------------
-- All_Sites_Are_Trusted --
---------------------------

function All_Sites_Are_Trusted (For_Community : Boolean) return Boolean is
Sites : constant Vector := Trusted_Sites (For_Community);
begin
return Sites.Length in 1 and then Sites (1) = "...";
end All_Sites_Are_Trusted;

----------------
-- Is_Trusted --
----------------

function Is_Trusted (URL : Alire.URL) return Boolean
is (for some Site of Trusted_Sites => URI.Host (URL) = Site
or else Has_Suffix (URI.Host (URL), "." & Site));
function Is_Trusted (URL : Alire.URL; For_Community : Boolean)
return Boolean
is
Sites : constant Vector := Trusted_Sites (For_Community);
begin
return
All_Sites_Are_Trusted (For_Community)
or else (for some Site of Sites
=> URI.Host (URL) = Site
or else Has_Suffix (URI.Host (URL), "." & Site));
end Is_Trusted;

----------------------
-- Local_Repository --
Expand Down Expand Up @@ -1452,11 +1481,16 @@ package body Alire.Publish is
-- Print_Trusted_Sites --
-------------------------

procedure Print_Trusted_Sites is
procedure Print_Trusted_Sites (For_Community : Boolean) is
Sites : constant Vector := Trusted_Sites (For_Community);
begin
for Site of Trusted_Sites loop
Trace.Always (Site);
end loop;
if All_Sites_Are_Trusted (For_Community) then
Trace.Always ("All sites are currently trusted for private indexes.");
else
for Site of Sites loop
Trace.Always (Site);
end loop;
end if;
end Print_Trusted_Sites;

end Alire.Publish;
16 changes: 11 additions & 5 deletions src/alire/alire-publish.ads
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,17 @@ package Alire.Publish is
& M.Crate.As_String & "-"
& M.Version.Image);

procedure Print_Trusted_Sites;
-- Print our list of allowed sites to host git releases

function Is_Trusted (URL : Alire.URL) return Boolean;
-- According to our whitelist
procedure Print_Trusted_Sites (For_Community : Boolean);
-- Print our list of allowed sites to host git releases.
--
-- If For_Community is True, the list is the hardcoded
-- Community_Trusted_Sites list, otherwise it is that configured with the
-- 'origins.git.trusted_sites' setting.

function Is_Trusted (URL : Alire.URL; For_Community : Boolean)
return Boolean;
-- According to the 'origins.git.trusted_sites' setting, or the hardcoded
-- Community_Trusted_Sites if For_Community is True.

type Data is tagged limited private;

Expand Down
12 changes: 12 additions & 0 deletions src/alire/alire-settings-builtins.ads
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ package Alire.Settings.Builtins is
& " character. The token ${DEST} is replaced by the destination path,"
& " and ${URL} by the URL to download.");

Origins_Git_Trusted_Sites : constant Builtin := New_Builtin
(Key => "origins.git.trusted_sites",
Kind => Stn_String,
Def => Community_Trusted_Sites,
Global_Only => True,
Help =>
"Space-separated list of trusted sites for Git origins, used by"
& " 'alr index --check' and 'alr publish --for-private-index'. If set to"
& " '...', all origins are trusted. Note that this does not have any"
& " effect when using 'alr publish' for submissions to the community"
& " index (which only permits the default list).");

-- SOLVER

Solver_Autonarrow : constant Builtin := New_Builtin
Expand Down
11 changes: 11 additions & 0 deletions src/alire/alire.ads
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ package Alire with Preelaborate is
Extension_Separator : constant Character := '.';
-- Refers to extension releases! Nothing to do with files

Community_Trusted_Sites : constant String :=
"bitbucket.org"
& " github.com"
& " gitlab.com"
& " savannah.gnu.org"
& " savannah.nongnu.org"
& " sf.net";
-- Space separated list of hosts that are known to not be vulnerable to
-- SHA-1 collision attacks, and therefore trusted for use on the community
-- index. Also used as the default value for 'origins.git.trusted_sites'.

-- Strings that are used quite generally

package UStrings renames Ada.Strings.Unbounded;
Expand Down
3 changes: 2 additions & 1 deletion src/alr/alr-commands-publish.adb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ package body Alr.Commands.Publish is
Cmd.Auto_Update_Index;

if Cmd.Print_Trusted then
Alire.Publish.Print_Trusted_Sites;
Alire.Publish.Print_Trusted_Sites
(For_Community => not Cmd.For_Private_Index);

elsif Cmd.Tar then

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
description = "Sample crate"
name = "crate"
version = "1.0.0"
licenses = "GPL-3.0-only"
maintainers = ["any@bo.dy"]
maintainers-logins = ["someone"]

[origin]
url = "git+https://some.host/path/to/repo"
commit = "0000000000000000000000000000000000000000"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = "1.1"
77 changes: 77 additions & 0 deletions testsuite/tests/index/untrusted-host/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Check detection of untrusted hosts when running `alr index --check`
"""


import os

from drivers.alr import run_alr, alr_settings_set
from drivers.asserts import assert_eq, assert_match
from drivers.helpers import replace_in_file


# `alr index --check` should fail due to untrusted host.
p = run_alr("index", "--check", quiet=False, complain_on_error=False)
assert_match(
(
r"Warning: Release crate=1\.0\.0 has URL not in known hosts: "
r"https://some\.host/path/to/repo"
r".*ERROR: Issues were found in index contents"
),
p.out
)

# Configure the untrusted host as trusted.
alr_settings_set("origins.git.trusted_sites", "github.com some.host gitlab.com")

# `alr index --check` should now succeed.
p = run_alr("index", "--check", quiet=False)
assert_eq("Success: No issues found in index contents.\n", p.out)

# Change the index manifest to use a new untrusted host, and check that
# `alr index --check` fails again.
manifest_path = os.path.join(
"my_index", "index", "cr", "crate", "crate-1.0.0.toml"
)
replace_in_file(
manifest_path,
"git+https://some.host/path/to/repo",
"git+https://untrusted.host/path/to/repo"
)
p = run_alr("index", "--check", quiet=False, complain_on_error=False)
assert_match(
(
r"Warning: Release crate=1\.0\.0 has URL not in known hosts: "
r"https://untrusted\.host/path/to/repo"
r".*ERROR: Issues were found in index contents"
),
p.out
)

# Verify that it still fails when the host has a trailing dot (note the double
# space in the setting value, which was causing the empty string to be
# considered a trusted host, and hence `untrusted.host.` to be considered a
# trusted subdomain thereof).
replace_in_file(
manifest_path,
"git+https://untrusted.host/path/to/repo",
"git+https://untrusted.host./path/to/repo"
)
p = run_alr("index", "--check", quiet=False, complain_on_error=False)
assert_match(
(
r"Warning: Release crate=1\.0\.0 has URL not in known hosts: "
r"https://untrusted\.host\./path/to/repo"
r".*ERROR: Issues were found in index contents"
),
p.out
)

# Set 'origins.git.trusted_sites' to '...' and verify that all hosts are now
# permitted.
alr_settings_set("origins.git.trusted_sites", "...")
p = run_alr("index", "--check", quiet=False)
assert_eq("Success: No issues found in index contents.\n", p.out)


print("SUCCESS")
4 changes: 4 additions & 0 deletions testsuite/tests/index/untrusted-host/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
driver: python-script
indexes:
my_index:
in_fixtures: false
Loading

0 comments on commit 09b3893

Please sign in to comment.