Skip to content

Commit 50969b2

Browse files
authored
Merge branch 'main' into buildkit-providerless
2 parents 2345db3 + f76070e commit 50969b2

File tree

9 files changed

+148
-25
lines changed

9 files changed

+148
-25
lines changed

.cargo/audit.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[advisories]
2+
ignore = [
3+
# This advisory comes from `russh -> rsa` which is optional dependency
4+
"RUSTSEC-2023-0071",
5+
]
6+
7+
[output]
8+
deny = ["warnings"]
9+
quiet = false

.github/workflows/audit.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Security audit
2+
on:
3+
workflow_dispatch:
4+
push:
5+
paths:
6+
- '**/Cargo.toml'
7+
- '**/Cargo.lock'
8+
jobs:
9+
security_audit:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Generate Cargo.lock if doesn't exist
14+
run: |
15+
if [ ! -f Cargo.lock ]; then
16+
cargo generate-lockfile
17+
fi
18+
- uses: rustsec/[email protected]
19+
with:
20+
token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/ci.yml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@ jobs:
3131
- uses: taiki-e/install-action@v2
3232
with:
3333
tool: cargo-hack
34-
- name: Build (without host-port-exposure)
35-
run: cargo hack build --feature-powerset --depth 2 --keep-going --exclude-features host-port-exposure
36-
- name: Build (host-port-exposure with TLS backend)
37-
run: cargo hack build --feature-powerset --depth 2 --keep-going --include-features host-port-exposure,ring,aws-lc-rs --at-least-one-of ring,aws-lc-rs
34+
- name: Build
35+
run: cargo hack build --feature-powerset --depth 2 --clean-per-run
3836

3937
test:
4038
name: Test
@@ -68,10 +66,8 @@ jobs:
6866
- uses: taiki-e/install-action@v2
6967
with:
7068
tool: cargo-hack
71-
- name: Tests (without host-port-exposure)
72-
run: cargo hack test --feature-powerset --depth 2 --clean-per-run --partition ${{ matrix.partition }} --exclude-features host-port-exposure
73-
- name: Tests (host-port-exposure with TLS backend)
74-
run: cargo hack test --feature-powerset --depth 2 --clean-per-run --partition ${{ matrix.partition }} --include-features host-port-exposure,ring,aws-lc-rs --at-least-one-of ring,aws-lc-rs
69+
- name: Tests
70+
run: cargo hack test --feature-powerset --depth 2 --clean-per-run --partition ${{ matrix.partition }}
7571

7672
fmt:
7773
name: Rustfmt check

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,42 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [0.25.2] - 2025-10-27
6+
### Details
7+
#### Features
8+
- Platform config passing through ImageExt trait ([#838](https://github.com/testcontainers/testcontainers-rs/pull/838))
9+
10+
#### Miscellaneous Tasks
11+
- Remove usage of reqwest hickory dns feature ([#860](https://github.com/testcontainers/testcontainers-rs/pull/860))
12+
- Drop weak dependencies due to cargo bug ([#862](https://github.com/testcontainers/testcontainers-rs/pull/862))
13+
14+
## [0.25.1] - 2025-10-27
15+
### Details
16+
#### Bug Fixes
17+
- Replace tokio-tar with astral-tokio-tar ([#852](https://github.com/testcontainers/testcontainers-rs/pull/852))
18+
19+
#### Documentation
20+
- Rustdoc for builder API ([#820](https://github.com/testcontainers/testcontainers-rs/pull/820))
21+
22+
#### Features
23+
- Use DOCKER_DEFAULT_PLATFORM env var to specify platform ([#800](https://github.com/testcontainers/testcontainers-rs/pull/800))
24+
- Fallback to platform linux/amd64 when image pull fails ([#837](https://github.com/testcontainers/testcontainers-rs/pull/837))
25+
- Add support for devices request ([#832](https://github.com/testcontainers/testcontainers-rs/pull/832))
26+
- Add configurable tmpfs mount sizes ([#853](https://github.com/testcontainers/testcontainers-rs/pull/853))
27+
- Support `http_wait` functionallity without tls dependencies ([#850](https://github.com/testcontainers/testcontainers-rs/pull/850))
28+
- Add container hostname support ([#848](https://github.com/testcontainers/testcontainers-rs/pull/848))
29+
- Expose host ports between host and containers via ssh sidecar ([#846](https://github.com/testcontainers/testcontainers-rs/pull/846))
30+
31+
#### Miscellaneous Tasks
32+
- Update bollard-stubs requirement from =1.48.3-rc.28.0.4 to =1.49.0-rc.28.3.3 ([#828](https://github.com/testcontainers/testcontainers-rs/pull/828))
33+
34+
#### Refactor
35+
- Remove bollard_stubs dependency as bollard re-exports it ([#844](https://github.com/testcontainers/testcontainers-rs/pull/844))
36+
37+
#### Testing
38+
- Avoid flakiness in `platform` test
39+
- Switch to testcontainers/helloworld and reduce some flakiness ([#855](https://github.com/testcontainers/testcontainers-rs/pull/855))
40+
541
## [0.25.0] - 2025-07-27
642
### Details
743
#### Bug Fixes

testcontainers/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "testcontainers"
3-
version = "0.25.0"
3+
version = "0.25.2"
44
categories = ["development-tools::testing"]
55
readme = "README.md"
66
authors.workspace = true
@@ -49,17 +49,17 @@ url = { version = "2", features = ["serde"] }
4949

5050
[features]
5151
default = ["ring"]
52-
ring = ["bollard/ssl", "russh?/ring"]
53-
aws-lc-rs = ["bollard/aws-lc-rs", "russh?/aws-lc-rs"]
52+
ring = ["bollard/ssl"]
53+
aws-lc-rs = ["bollard/aws-lc-rs"]
5454
ssl = ["bollard/ssl_providerless"]
5555
blocking = []
5656
watchdog = ["signal-hook", "conquer-once"]
57-
http_wait = ["http_wait_plain", "reqwest/rustls-tls", "reqwest/rustls-tls-native-roots", "reqwest/hickory-dns"]
57+
http_wait = ["http_wait_plain", "reqwest/rustls-tls", "reqwest/rustls-tls-native-roots"]
5858
http_wait_plain = ["reqwest"]
5959
properties-config = ["serde-java-properties"]
6060
reusable-containers = []
6161
device-requests = []
62-
host-port-exposure = ["dep:russh"]
62+
host-port-exposure = ["dep:russh", "russh/ring"]
6363

6464
[dev-dependencies]
6565
anyhow = "1.0.86"

testcontainers/src/core/client.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,18 @@ impl Client {
508508
Ok(())
509509
}
510510

511-
pub(crate) async fn pull_image(&self, descriptor: &str) -> Result<(), ClientError> {
511+
pub(crate) async fn pull_image(
512+
&self,
513+
descriptor: &str,
514+
platform: Option<String>,
515+
) -> Result<(), ClientError> {
512516
let pull_options = CreateImageOptionsBuilder::new()
513517
.from_image(descriptor)
514-
.platform(self.config.platform().unwrap_or_default())
518+
.platform(
519+
platform
520+
.as_deref()
521+
.unwrap_or_else(|| self.config.platform().unwrap_or_default()),
522+
)
515523
.build();
516524

517525
let credentials = self.credentials_for_image(descriptor).await;
@@ -525,7 +533,7 @@ impl Client {
525533
Err(BollardError::DockerResponseServerError {
526534
status_code: _,
527535
message: _,
528-
}) => {
536+
}) if !matches!(platform.as_deref(), Some("linux/amd64")) => {
529537
self.pull_image_linux_amd64(descriptor).await?;
530538
}
531539
_ => {
@@ -789,7 +797,7 @@ mod tests {
789797
)
790798
.await;
791799

792-
client.pull_image(IMAGE).await?;
800+
client.pull_image(IMAGE, None).await?;
793801

794802
let image = client.bollard.inspect_image(IMAGE).await?;
795803

@@ -804,7 +812,7 @@ mod tests {
804812
.remove_image(IMAGE, Option::<RemoveImageOptions>::None, credentials)
805813
.await?;
806814

807-
client.pull_image(IMAGE).await?;
815+
client.pull_image(IMAGE, None).await?;
808816

809817
let image = client.bollard.inspect_image(IMAGE).await?;
810818

testcontainers/src/core/containers/request.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct ContainerRequest<I: Image> {
2626
pub(crate) image_name: Option<String>,
2727
pub(crate) image_tag: Option<String>,
2828
pub(crate) container_name: Option<String>,
29+
pub(crate) platform: Option<String>,
2930
pub(crate) network: Option<String>,
3031
pub(crate) hostname: Option<String>,
3132
pub(crate) labels: BTreeMap<String, String>,
@@ -97,6 +98,10 @@ impl<I: Image> ContainerRequest<I> {
9798
&self.container_name
9899
}
99100

101+
pub fn platform(&self) -> &Option<String> {
102+
&self.platform
103+
}
104+
100105
pub fn env_vars(&self) -> impl Iterator<Item = (Cow<'_, str>, Cow<'_, str>)> {
101106
self.image
102107
.env_vars()
@@ -248,6 +253,7 @@ impl<I: Image> From<I> for ContainerRequest<I> {
248253
image_name: None,
249254
image_tag: None,
250255
container_name: None,
256+
platform: None,
251257
network: None,
252258
hostname: None,
253259
labels: BTreeMap::default(),
@@ -307,6 +313,7 @@ impl<I: Image + Debug> Debug for ContainerRequest<I> {
307313
.field("image_name", &self.image_name)
308314
.field("image_tag", &self.image_tag)
309315
.field("container_name", &self.container_name)
316+
.field("platform", &self.platform)
310317
.field("network", &self.network)
311318
.field("hostname", &self.hostname)
312319
.field("labels", &self.labels)

testcontainers/src/core/image/image_ext.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,20 @@ pub trait ImageExt<I: Image> {
6868
/// Sets the container name.
6969
fn with_container_name(self, name: impl Into<String>) -> ContainerRequest<I>;
7070

71+
/// Sets the platform the container will be run on.
72+
///
73+
/// Platform in the format `os[/arch[/variant]]` used for image lookup.
74+
///
75+
/// # Examples
76+
///
77+
/// ```rust,no_run
78+
/// use testcontainers::{GenericImage, ImageExt};
79+
///
80+
/// let image = GenericImage::new("image", "tag")
81+
/// .with_platform("linux/amd64");
82+
/// ```
83+
fn with_platform(self, platform: impl Into<String>) -> ContainerRequest<I>;
84+
7185
/// Sets the network the container will be connected to.
7286
fn with_network(self, network: impl Into<String>) -> ContainerRequest<I>;
7387

@@ -283,6 +297,15 @@ impl<RI: Into<ContainerRequest<I>>, I: Image> ImageExt<I> for RI {
283297
}
284298
}
285299

300+
fn with_platform(self, platform: impl Into<String>) -> ContainerRequest<I> {
301+
let container_req = self.into();
302+
303+
ContainerRequest {
304+
platform: Some(platform.into()),
305+
..container_req
306+
}
307+
}
308+
286309
fn with_network(self, network: impl Into<String>) -> ContainerRequest<I> {
287310
let container_req = self.into();
288311
ContainerRequest {

testcontainers/src/runners/async_runner.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,27 @@ where
187187
None
188188
};
189189

190+
let mut options_builder: Option<CreateContainerOptionsBuilder> = None;
191+
190192
// name of the container
191193
if let Some(name) = container_req.container_name() {
192-
let options = CreateContainerOptionsBuilder::new()
193-
.name(name)
194-
.platform(client.config.platform().unwrap_or_default())
195-
.build();
196-
create_options = Some(options)
194+
let options = CreateContainerOptionsBuilder::new().name(name);
195+
196+
options_builder = Some(options);
197+
}
198+
199+
// platform of the container
200+
if let Some(platform) = container_req.platform() {
201+
let options = options_builder.unwrap_or(CreateContainerOptionsBuilder::new());
202+
options_builder = Some(options.platform(platform));
203+
} else {
204+
// set platform from global platform setting if available
205+
let options = options_builder.unwrap_or(CreateContainerOptionsBuilder::new());
206+
options_builder = Some(options.platform(client.config.platform().unwrap_or_default()));
207+
}
208+
209+
if let Some(options) = options_builder {
210+
create_options = Some(options.build());
197211
}
198212

199213
// handle environment variables
@@ -311,7 +325,12 @@ where
311325
status_code: 404, ..
312326
},
313327
)) => {
314-
client.pull_image(&container_req.descriptor()).await?;
328+
client
329+
.pull_image(
330+
&container_req.descriptor(),
331+
container_req.platform().clone(),
332+
)
333+
.await?;
315334
client.create_container(create_options, config).await
316335
}
317336
res => res,
@@ -361,7 +380,12 @@ where
361380
async fn pull_image(self) -> Result<ContainerRequest<I>> {
362381
let container_req = self.into();
363382
let client = Client::lazy_client().await?;
364-
client.pull_image(&container_req.descriptor()).await?;
383+
client
384+
.pull_image(
385+
&container_req.descriptor(),
386+
container_req.platform().clone(),
387+
)
388+
.await?;
365389

366390
Ok(container_req)
367391
}

0 commit comments

Comments
 (0)