Skip to content

Commit 12590ee

Browse files
committed
chore(merge): merge branch 'feat/fido-device-onboard' into release-1.3
2 parents 71c35c4 + 4fe8576 commit 12590ee

File tree

115 files changed

+9904
-38
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+9904
-38
lines changed

.github/workflows/astarte-end-to-end-test-workflow.yaml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ on:
2424
env:
2525
elixir_version: "1.15"
2626
otp_version: "26.1"
27+
CLEA_DEV_BASE: ""
28+
CLEA_DEV_REALM: ""
29+
CLEA_DEV_REALM_TOKEN: ""
30+
BOARD_BASE_URL: ""
2731

2832
jobs:
2933
e2e-build:
3034
uses: ./.github/workflows/astarte-e2e-build-workflow.yaml
35+
3136
astarte-build:
3237
uses: ./.github/workflows/astarte-build-workflow.yaml
3338

@@ -60,6 +65,80 @@ jobs:
6065
wget https://github.com/astarte-platform/wait-for-astarte-docker-compose/releases/download/v1.1.0/wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
6166
tar xf wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
6267
./wait-for-astarte-docker-compose
68+
- uses: actions/checkout@v2
69+
- name: Initialize docker compose files
70+
run: docker run -v $(pwd)/compose:/compose astarte/docker-compose-initializer
71+
- name: Restore astarte images
72+
uses: actions/download-artifact@v4
73+
with:
74+
name: astarte-images
75+
path: ${{ runner.temp }}
76+
- name: Restore astarte e2e image
77+
uses: actions/download-artifact@v4
78+
with:
79+
name: astarte-e2e-image
80+
path: ${{ runner.temp }}
81+
- name: Load astarte images
82+
run: ls ${{ runner.temp }}/*.tar | xargs --max-args 1 docker load --input
83+
- name: Start all Astarte services
84+
run: docker compose up -d
85+
- name: Wait for Astarte to come up
86+
run: |
87+
wget https://github.com/astarte-platform/wait-for-astarte-docker-compose/releases/download/v1.1.0/wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
88+
tar xf wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
89+
./wait-for-astarte-docker-compose
90+
- name: Install astartectl
91+
run: |
92+
wget https://github.com/astarte-platform/astartectl/releases/download/v22.11.02/astartectl_22.11.02_linux_x86_64.tar.gz
93+
tar xf astartectl_22.11.02_linux_x86_64.tar.gz
94+
chmod +x astartectl
95+
- name: Generate realm keypair and JWT
96+
run: |
97+
./astartectl utils gen-keypair test
98+
E2E_HOUSEKEEPING_API_JWT=$(./astartectl utils gen-jwt housekeeping -k compose/astarte-keys/housekeeping_private.pem)
99+
echo "E2E_HOUSEKEEPING_API_JWT=$E2E_HOUSEKEEPING_API_JWT" >> $GITHUB_ENV
100+
- name: Generate JWT
101+
run: |
102+
JWT=$(./astartectl utils gen-jwt appengine channels pairing realm-management -k test_private.pem)
103+
echo "E2E_JWT=$JWT" >> $GITHUB_ENV
104+
- name: Run Astarte E2E
105+
working-directory: tools/astarte_e2e
106+
env:
107+
E2E_HOST: "astarte-e2e"
108+
E2E_PAIRING_URL: http://api.astarte.localhost/pairing
109+
E2E_APPENGINE_URL: http://api.astarte.localhost/appengine
110+
E2E_HOUSEKEEPING_URL: http://api.astarte.localhost/housekeeping
111+
E2E_REALM_MANAGEMENT_URL: http://api.astarte.localhost/realmmanagement
112+
E2E_AMQP_CONSUMER_HOST: rabbitmq
113+
E2E_IGNORE_SSL_ERRORS: true
114+
E2E_CHECK_INTERVAL_SECONDS: 5
115+
E2E_CHECK_REPETITIONS: 5
116+
E2E_MAILER_TO_ADDRESS: mail@example.com
117+
E2E_MAIL_SUBJECT: "Subj: Astarte Notification"
118+
run: |
119+
docker run \
120+
-e E2E_REALM_PUBLIC_KEY_PEM="$(cat ../../test_public.pem)" \
121+
--env-file=<(env | grep '^E2E_' | grep -v '^E2E_REALM_PUBLIC_KEY_PEM=') \
122+
--network astarte \
123+
--hostname "$E2E_HOST" \
124+
astarte-e2e
125+
- name: Check Docker
126+
if: ${{ failure() }}
127+
run: docker compose logs
128+
- name: Bring down Astarte docker-compose
129+
run: docker compose down
130+
131+
fdo-end-to-end:
132+
needs: [astarte-build]
133+
name: FDO end-to-end Test
134+
runs-on: ubuntu-24.04
135+
steps:
136+
- name: Checkout fdo e2e repo
137+
uses: actions/checkout@v6
138+
with:
139+
repository: astarte-platform/astarte-device-fdo-rust
140+
ref: dev
141+
- uses: ./.github/actions/install-deps
63142
- name: Install astartectl
64143
run: |
65144
wget https://github.com/astarte-platform/astartectl/releases/download/v22.11.02/astartectl_22.11.02_linux_x86_64.tar.gz
@@ -100,3 +179,61 @@ jobs:
100179
run: docker compose logs
101180
- name: Bring down Astarte docker-compose
102181
run: docker compose down
182+
mkdir -p ${{ runner.temp }}/bin
183+
mv ./astartectl ${{ runner.temp }}/bin
184+
echo ${{ runner.temp }}/bin >> "$GITHUB_PATH"
185+
- name: Install additional dependencies
186+
run: |
187+
sudo apt-get install -y openssl jq
188+
- uses: actions/checkout@v6
189+
name: checkout astarte
190+
with:
191+
path: .tmp/repos/astarte
192+
- name: Restore astarte images
193+
uses: actions/download-artifact@v4
194+
with:
195+
name: astarte-images
196+
path: ${{ runner.temp }}
197+
- name: Initialize keys
198+
working-directory: .tmp/repos/astarte
199+
run: |
200+
docker run -v $(pwd)/compose:/compose astarte/docker-compose-initializer
201+
astartectl utils gen-keypair test
202+
- name: Load astarte images
203+
run: ls ${{ runner.temp }}/*.tar | xargs --max-args 1 docker load --input
204+
- name: Enable FDO
205+
run: echo "PAIRING_ENABLE_FDO=true" >> .tmp/repos/astarte/.env
206+
- name: Start all Astarte services
207+
working-directory: .tmp/repos/astarte
208+
run: docker compose up -d
209+
- uses: actions-rust-lang/setup-rust-toolchain@v1.15.2
210+
- uses: mozilla-actions/sccache-action@v0.0.9
211+
- name: Cache container build
212+
id: cache-container
213+
uses: actions/cache@v4.3.0
214+
with:
215+
path: .tmp/cache/containers
216+
key: ${{ runner.os }}-${{ hashFiles('justfile', 'scripts/**/*.sh', 'containers/**') }}
217+
- name: Install just
218+
uses: taiki-e/install-action@v2.49.43
219+
with:
220+
tool: just
221+
- run: just go-server-setup
222+
- name: Wait for Astarte to come up
223+
run: |
224+
wget https://github.com/astarte-platform/wait-for-astarte-docker-compose/releases/download/v1.1.0/wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
225+
tar xf wait-for-astarte-docker-compose_1.1.0_linux_amd64.tar.gz
226+
./wait-for-astarte-docker-compose
227+
- name: Create realm
228+
working-directory: .tmp/repos/astarte
229+
run: |
230+
astartectl housekeeping realms create -y "test" \
231+
--astarte-url "http://api.astarte.localhost" \
232+
--realm-public-key "test_public.pem" \
233+
-k compose/astarte-keys/housekeeping_private.pem
234+
- name: Run FDO
235+
run: just astarte-run
236+
- name: Check Docker
237+
working-directory: .tmp/repos/astarte
238+
if: ${{ failure() }}
239+
run: docker compose logs astarte-pairing

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2121

2222
## [1.3.0-rc.1] - 2026-01-26
2323

24+
## [1.3.0] - Unreleased
25+
- [astarte_pairing] FDO authentication (EXPERIMENTAL feature, disabled by default). New environment variables are needed in order to use FDO:
26+
- `PAIRING_ENABLE_FDO` - whether the FDO feature is enabled or not (default: false)
27+
- `PAIRING_FDO_RENDEZVOUS_URL` - URL of the rendezvous server (default: "http://rendezvous:8041")
28+
- `ASTARTE_BASE_URL_DOMAIN` - domain part of the base URL of astarte, used by devices to connect in TO2 phase (required if FDO enabled)
29+
- `ASTARTE_BASE_URL_PORT` - port of the base URL of astarte (required if FDO enabled)
30+
- `ASTARTE_BASE_URL_PROTOCOL` - protocol of the base URL of astarte (required if FDO enabled)
31+
32+
## [1.3.0-rc.0] - 2025-11-21
2433
### Added
2534

2635
- New environment variables for trigger notifications between realm management replicas and realm management -> pairing. These variables are currently being used only by realm management

apps/astarte_appengine_api/test/support/helpers/database.ex

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,15 @@ defmodule Astarte.Helpers.Database do
109109
);
110110
"""
111111

112+
@create_ownership_vouchers_table """
113+
CREATE TABLE #{Realm.keyspace_name(@test_realm)}.ownership_vouchers (
114+
private_key blob,
115+
voucher_data blob,
116+
device_id uuid,
117+
PRIMARY KEY (device_id, voucher_data)
118+
);
119+
"""
120+
112121
@create_devices_table """
113122
CREATE TABLE #{Realm.keyspace_name(@test_realm)}.devices (
114123
device_id uuid,
@@ -435,6 +444,8 @@ defmodule Astarte.Helpers.Database do
435444
{:ok, _} ->
436445
Repo.query!(@create_capabilities_type)
437446

447+
Repo.query!(@create_ownership_vouchers_table)
448+
438449
Repo.query!(@create_devices_table)
439450

440451
Repo.query!(@create_deletion_in_progress_table)

apps/astarte_appengine_api/test/support/helpers/database_v2.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ defmodule Astarte.Helpers.DatabaseV2 do
6969
);
7070
"""
7171

72+
@create_ownership_vouchers_table """
73+
CREATE TABLE :keyspace.ownership_vouchers (
74+
private_key blob,
75+
voucher_data blob,
76+
device_id uuid,
77+
PRIMARY KEY (device_id, voucher_data)
78+
);
79+
"""
80+
7281
@create_devices_table """
7382
CREATE TABLE :keyspace.devices (
7483
device_id uuid,
@@ -249,6 +258,7 @@ defmodule Astarte.Helpers.DatabaseV2 do
249258
realm_keyspace = Realm.keyspace_name(realm_name)
250259
execute!(realm_keyspace, @create_keyspace)
251260
execute!(realm_keyspace, @create_capabilities_type)
261+
execute!(realm_keyspace, @create_ownership_vouchers_table)
252262
execute!(realm_keyspace, @create_devices_table)
253263
execute!(realm_keyspace, @create_groups_table)
254264
execute!(realm_keyspace, @create_names_table)

apps/astarte_data_updater_plant/test/support/database_test_helper.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,15 @@ defmodule Astarte.DataUpdaterPlant.DatabaseTestHelper do
5353
);
5454
"""
5555

56+
@create_ownership_vouchers_table """
57+
CREATE TABLE :keyspace.ownership_vouchers (
58+
private_key blob,
59+
voucher_data blob,
60+
device_id uuid,
61+
PRIMARY KEY (device_id, voucher_data)
62+
);
63+
"""
64+
5665
@create_devices_table """
5766
CREATE TABLE :keyspace.devices (
5867
device_id uuid,
@@ -369,6 +378,7 @@ defmodule Astarte.DataUpdaterPlant.DatabaseTestHelper do
369378
case execute(keyspace_name, @create_autotestrealm) do
370379
{:ok, _} ->
371380
execute!(keyspace_name, @create_capabilities_type)
381+
execute!(keyspace_name, @create_ownership_vouchers_table)
372382
execute!(keyspace_name, @create_devices_table)
373383
execute!(keyspace_name, @create_endpoints_table)
374384

apps/astarte_data_updater_plant/test/support/helpers/database.ex

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ defmodule Astarte.Helpers.Database do
7575
);
7676
"""
7777

78+
@create_ownership_vouchers_table """
79+
CREATE TABLE :keyspace.ownership_vouchers (
80+
private_key blob,
81+
voucher_data blob,
82+
device_id uuid,
83+
PRIMARY KEY (device_id, voucher_data)
84+
);
85+
"""
86+
7887
@create_devices_table """
7988
CREATE TABLE :keyspace.devices (
8089
device_id uuid,
@@ -101,7 +110,6 @@ defmodule Astarte.Helpers.Database do
101110
last_seen_ip inet,
102111
attributes map<varchar, varchar>,
103112
capabilities capabilities,
104-
105113
groups map<text, timeuuid>,
106114
107115
PRIMARY KEY (device_id)
@@ -319,6 +327,19 @@ defmodule Astarte.Helpers.Database do
319327
execute!(realm_keyspace, @create_individual_datastreams_table, [], timeout: 60_000)
320328
execute!(realm_keyspace, @create_interfaces_table, [], timeout: 60_000)
321329
execute!(realm_keyspace, @create_deletion_in_progress_table, [], timeout: 60_000)
330+
execute!(realm_keyspace, @create_keyspace)
331+
execute!(realm_keyspace, @create_capabilities_type)
332+
execute!(realm_keyspace, @create_ownership_vouchers_table)
333+
execute!(realm_keyspace, @create_devices_table)
334+
execute!(realm_keyspace, @create_groups_table)
335+
execute!(realm_keyspace, @create_names_table)
336+
execute!(realm_keyspace, @create_kv_store)
337+
execute!(realm_keyspace, @create_endpoints_table)
338+
execute!(realm_keyspace, @create_simple_triggers_table)
339+
execute!(realm_keyspace, @create_individual_properties_table)
340+
execute!(realm_keyspace, @create_individual_datastreams_table)
341+
execute!(realm_keyspace, @create_interfaces_table)
342+
execute!(realm_keyspace, @create_deletion_in_progress_table)
322343

323344
Enum.each(@insert_endpoints, fn query ->
324345
execute!(realm_keyspace, query, [], timeout: 60_000)

apps/astarte_housekeeping/lib/astarte_housekeeping/realms/queries.ex

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ defmodule Astarte.Housekeeping.Realms.Queries do
260260
:ok <- create_simple_triggers_table(keyspace_name),
261261
:ok <- create_grouped_devices_table(keyspace_name),
262262
:ok <- create_deletion_in_progress_table(keyspace_name),
263+
:ok <- create_ownership_vouchers_table(keyspace_name),
264+
:ok <- create_to2_sessions_table(keyspace_name),
263265
:ok <- insert_realm_public_key(keyspace_name, public_key_pem),
264266
:ok <- insert_realm_astarte_schema_version(keyspace_name),
265267
:ok <- insert_realm(realm_name, device_limit),
@@ -599,6 +601,58 @@ defmodule Astarte.Housekeeping.Realms.Queries do
599601
end
600602
end
601603

604+
defp create_ownership_vouchers_table(keyspace_name) do
605+
query = """
606+
CREATE TABLE #{keyspace_name}.ownership_vouchers (
607+
private_key blob,
608+
voucher_data blob,
609+
guid blob,
610+
PRIMARY KEY (guid)
611+
);
612+
"""
613+
614+
with {:ok, %{rows: nil, num_rows: 1}} <- CSystem.execute_schema_change(query) do
615+
:ok
616+
end
617+
end
618+
619+
defp create_to2_sessions_table(keyspace_name) do
620+
query = """
621+
CREATE TABLE #{keyspace_name}.to2_sessions (
622+
guid blob,
623+
device_id uuid,
624+
hmac blob,
625+
nonce blob,
626+
sig_type int,
627+
epid_group blob,
628+
device_public_key blob,
629+
prove_dv_nonce blob,
630+
setup_dv_nonce blob,
631+
kex_suite_name ascii,
632+
cipher_suite_name int,
633+
max_owner_service_info_size int,
634+
owner_random blob,
635+
secret blob,
636+
sevk blob,
637+
svk blob,
638+
sek blob,
639+
device_service_info map<tuple<text, text>, blob>,
640+
owner_service_info list<blob>,
641+
last_chunk_sent int,
642+
replacement_guid blob,
643+
replacement_rv_info blob,
644+
replacement_pub_key blob,
645+
replacement_hmac blob,
646+
PRIMARY KEY (guid)
647+
)
648+
WITH default_time_to_live = 7200;
649+
"""
650+
651+
with {:ok, %{rows: nil, num_rows: 1}} <- CSystem.execute_schema_change(query) do
652+
:ok
653+
end
654+
end
655+
602656
defp create_grouped_devices_table(keyspace_name) do
603657
query = """
604658
CREATE TABLE #{keyspace_name}.grouped_devices (
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CREATE TABLE :keyspace.ownership_vouchers (
2+
private_key blob,
3+
voucher_data blob,
4+
guid blob,
5+
PRIMARY KEY (guid)
6+
);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
CREATE TABLE :keyspace.to2_sessions (
2+
guid blob,
3+
device_id uuid,
4+
hmac blob,
5+
nonce blob,
6+
sig_type int,
7+
epid_group blob,
8+
device_public_key blob,
9+
prove_dv_nonce blob,
10+
setup_dv_nonce blob,
11+
kex_suite_name ascii,
12+
cipher_suite_name int,
13+
max_owner_service_info_size int,
14+
owner_random blob,
15+
secret blob,
16+
sevk blob,
17+
svk blob,
18+
sek blob,
19+
device_service_info map<tuple<text, text>, blob>,
20+
owner_service_info list<blob>,
21+
last_chunk_sent int,
22+
replacement_guid blob,
23+
replacement_rv_info blob,
24+
replacement_pub_key blob,
25+
replacement_hmac blob,
26+
PRIMARY KEY (guid)
27+
)
28+
WITH default_time_to_live = 7200;

0 commit comments

Comments
 (0)