diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index a4c5536..17f0b06 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -32,6 +32,7 @@ jobs: - run: zig build -Dtarget=riscv64-linux - run: zig build -Dtarget=x86_64-macos - run: zig build -Dtarget=aarch64-macos + - run: ( cd example && zig build ) # Make sure example builds # Zig package manager expects everything to be inside a directory in the archive, # which it then strips out on download. So we need to shove everything inside a directory # the way GitHub/Gitea does for repo archives diff --git a/README.md b/README.md index bae5427..36cd75c 100644 --- a/README.md +++ b/README.md @@ -26,34 +26,39 @@ Building files from upstream AWS Go SDK v2, run the code generation, then build the main project with the generated code. Testing can be done with `zig test`. -Note that there are some loose ends on this version as compared to the [0.9.0 -branch](https://git.lerch.org/lobo/aws-sdk-for-zig/src/branch/0.9.0). More -details below in Limitations. This branch overall is superior, as is the 0.11 -compiler, but if you need an edge case and don't want to issue a PR, feel free -to use that branch. Using ----- This is designed for use with the Zig 0.11 package manager, and exposes a module called "aws". Set up `build.zig.zon` and add the dependency/module to your project -as normal and the package manager should do its thing. +as normal and the package manager should do its thing. A full example can be found +in [/example](example/README.md). -Running the demo ----------------- +Configuring the module and/or Running the demo +---------------------------------------------- This library mimics the aws c libraries for it's work, so it operates like most -other 'AWS things'. main.zig gives you a handful of examples for working with services. -For local testing or alternative endpoints, there's no real standard, so -there is code to look for `AWS_ENDPOINT_URL` environment variable that will -supersede all other configuration. Note that an alternative endpoint may -require passing in a client option to specify an different TLS root certificate -(pass null to disable certificate verification). +other 'AWS things'. [/src/main.zig](src/main.zig) gives you a handful of examples +for working with services. For local testing or alternative endpoints, there's +no real standard, so there is code to look for `AWS_ENDPOINT_URL` environment +variable that will supersede all other configuration. + +Other branches +-------------- + +The default branch is fully functional but requires TLS 1.3. Until AWS Services +support TLS 1.3 at the end of 2023, the [0.9.0 branch](https://git.lerch.org/lobo/aws-sdk-for-zig/src/branch/0.9.0) +may be of use. More details below in limitations. This branch overall is +superior, as is the 0.11 compiler, but if you need a service that doesn't support +TLS 1.3 and you need it right away, feel free to use that branch. Note I do not +intend to update code in the 0.9.0 branch, but will accept PRs. An [old branch based on aws-crt](https://github.com/elerch/aws-sdk-for-zig/tree/aws-crt) exists for posterity, and supports x86_64 linux. The old branch is deprecated, so if there are issues you see that work correctly in the aws-crt branch, please -file an issue. +file an issue. I can't think of a reason to use this branch any more. I do not +intend to entertain PRs on this branch, but reach out if you think it is important. Limitations ----------- @@ -85,3 +90,269 @@ TODO List: Compiler wishlist/watchlist: * [comptime allocations](https://github.com/ziglang/zig/issues/1291) so we can read files, etc (or is there another way) + +Services with TLS 1.3 Support (115 services) +-------------------------------------------- +``` +acm +amplify +apigateway +apigateway +appconfig +application-autoscaling +applicationinsights +apprunner +appstream2 +appsync +athena +backup +batch +cloud9 +clouddirectory +cloudformation +cloudhsmv2 +cloudsearch +cloudtrail +events +codeartifact +codebuild +codedeploy +codeguru-profiler +codepipeline +codestar-connections +comprehend +comprehendmedical +compute-optimizer +dms +databrew +dataexchange +datasync +devicefarm +directconnect +ds +ec2-instance-connect +api.ecr +api.ecr-public +ecs +elasticfilesystem +es +elastictranscoder +elasticmapreduce +events +finspace +finspace-api +fms +frauddetector +fsx +gamelift +glacier +globalaccelerator +glue +healthlake +honeycode +identitystore +inspector +iot +iotanalytics +iotevents +data.iotevents +api.iotwireless +ivs +kafka +kendra +kinesisanalytics +kms +lakeformation +license-manager +lookoutvision +metering.marketplace +mediaconnect +medialive +mediapackage-vod +mediastore +mgh +network-firewall +networkmanager +opsworks-cm +personalize +pinpoint +email +sms-voice.pinpoint +polly +qldb +session.qldb +quicksight +rds-data +redshift-data +rekognition +tagging +route53resolver +s3-outposts +api.sagemaker +edge.sagemaker +secretsmanager +servicecatalog +servicediscovery +servicequotas +email +states +snowball +ssm-contacts +swf +textract +transcribe +transfer +translate +waf-regional +workdocs +workmail +workmailmessageflow +workspaces +xray +``` + +Services without TLS 1.3 support (140 services) +----------------------------------------------- + +``` +access-analyzer +acm-pca +amplifybackend +execute-api +appflow +app-integrations +application-cost-profiler +discovery +appmesh +auditmanager +autoscaling +autoscaling-plans +budgets +chime +cloudfront +cloudsearchdomain +monitoring +logs +codecommit +codeguru-reviewer +codestar +codestar-notifications +cognito-identity +cognito-idp +cognito-sync +config +connect +contact-lens +participant.connect +ce +profile +datapipeline +dax +api.detective +devops-guru +dlm +dynamodb +streams.dynamodb +ebs +ec2 +eks +elasticache +elasticbeanstalk +api.elastic-inference +elasticloadbalancing +emr-containers +firehose +fis +forecast +forecastquery +greengrass +groundstation +guardduty +health +iam +imagebuilder +devices.iot1click +projects.iot1click +data.iot +api.iotdeviceadvisor +api.fleethub.iot +data.jobs.iot +api.tunneling.iot +iotsitewise +iotthingsgraph +kinesis +kinesisvideo +lambda +models.lex +models-v2-lex +runtime.lex +runtime-v2-lex +lightsail +geo +lookoutequipment +lookoutmetrics +machinelearning +macie +macie2 +managedblockchain +catalog.marketplace +marketplacecommerceanalytics +entitlement.marketplace +mediaconvert +mediapackage +data.mediastore +api.mediatailor +PlaybackEndpointPrefix +mgn +migrationhub-config +mobile +mq +mturk-requester +airflow +rds +nimble +opsworks +organizations +outposts +personalize-events +personalize-runtime +pi +api.pricing +ram +rds +redshift +resource-groups +robomaker +route53 +route53domains +s3 +s3-control +a2i-runtime.sagemaker +featurestore-runtime.sagemaker +runtime.sagemaker +savingsplans +schemas +securityhub +serverlessrepo +servicecatalog-appregistry +shield +signer +sms +sns +sqs +ssm +ssm-incidents +portal.sso +sso +oidc +storagegateway +sts +support +synthetics +query.timestream +ingest.timestream +waf +wafv2 +wellarchitected +worklink +``` diff --git a/example/build.zig b/example/build.zig new file mode 100644 index 0000000..d2ff66c --- /dev/null +++ b/example/build.zig @@ -0,0 +1,82 @@ +const std = @import("std"); + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "tmp", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + // const smithy_dep = b.dependency("smithy", .{ + // // These are the two arguments to the dependency. It expects a target and optimization level. + // .target = target, + // .optimize = optimize, + // }); + // exe.addModule("smithy", smithy_dep.module("smithy")); + const aws_dep = b.dependency("aws", .{ + // These are the two arguments to the dependency. It expects a target and optimization level. + .target = target, + .optimize = optimize, + }); + exe.addModule("aws", aws_dep.module("aws")); + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + const unit_tests = b.addTest(.{ + .root_source_file = .{ .path = "src/main.zig" }, + .target = target, + .optimize = optimize, + }); + + const run_unit_tests = b.addRunArtifact(unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_unit_tests.step); +} diff --git a/example/build.zig.zon b/example/build.zig.zon new file mode 100644 index 0000000..b7397ec --- /dev/null +++ b/example/build.zig.zon @@ -0,0 +1,15 @@ +.{ + .name = "myapp", + .version = "0.0.1", + + .dependencies = .{ + .aws = .{ + .url = "https://git.lerch.org/lobo/aws-sdk-for-zig/actions/runs/57/artifacts/27", + .hash = "1220c054e4ff05072b0eda6a2ab318cffe3a9356d70e0ec116e55835bf5e5c9baafd", + }, + .smithy = .{ + .url = "https://git.lerch.org/lobo/smithy/archive/41b61745d25a65817209dd5dddbb5f9b66896a99.tar.gz", + .hash = "122087deb0ae309b2258d59b40d82fe5921fdfc35b420bb59033244851f7f276fa34", + }, + }, +} diff --git a/example/src/main.zig b/example/src/main.zig new file mode 100644 index 0000000..20fb68c --- /dev/null +++ b/example/src/main.zig @@ -0,0 +1,62 @@ +const std = @import("std"); +const aws = @import("aws"); + +pub const std_options = struct { + pub const log_level: std.log.Level = .info; + + // usually log_level is enough, but log_scope_levels can be used + // for finer grained control + pub const log_scope_levels = &[_]std.log.ScopeLevel{ + .{ .scope = .awshttp, .level = .warn }, + }; +}; + +pub fn main() anyerror!void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + const stdout_raw = std.io.getStdOut().writer(); + var bw = std.io.bufferedWriter(stdout_raw); + defer bw.flush() catch unreachable; + const stdout = bw.writer(); + + // To use a proxy, uncomment the following with your own configuration + // const proxy = std.http.Proxy{ + // .protocol = .plain, + // .host = "localhost", + // .port = 8080, + // }; + // + // var client = aws.Client.init(allocator, .{ .proxy = proxy }); + var client = aws.Client.init(allocator, .{}); + defer client.deinit(); + + const options = aws.Options{ + .region = "us-west-2", + .client = client, + }; + + // As of 2023-08-28, only ECS from this list supports TLS v1.3 + // AWS commitment is to enable all services by 2023-12-31 + const services = aws.Services(.{ .sts, .kms }){}; + try stdout.print("Calling KMS ListKeys, a TLS 1.3 enabled service\n", .{}); + try stdout.print("You likely have at least some AWS-generated keys in your account,\n", .{}); + try stdout.print("but if the account has not had many services used, this may return 0 keys\n\n", .{}); + const call_kms = try aws.Request(services.kms.list_keys).call(.{}, options); + try stdout.print("\trequestId: {s}\n", .{call_kms.response_metadata.request_id}); + try stdout.print("\tkey count: {d}\n", .{call_kms.response.keys.?.len}); + for (call_kms.response.keys.?) |key| { + try stdout.print("\t\tkey id: {s}\n", .{key.key_id.?}); + try stdout.print("\t\tkey arn: {s}\n", .{key.key_arn.?}); + } + defer call_kms.deinit(); + + try stdout.print("\n\n\nCalling STS GetCallerIdentity. This does not have TLS 1.3 in September 2023\n", .{}); + try stdout.print("A failure may occur\n\n", .{}); + const call = try aws.Request(services.sts.get_caller_identity).call(.{}, options); + defer call.deinit(); + try stdout.print("\tarn: {s}\n", .{call.response.arn.?}); + try stdout.print("\tid: {s}\n", .{call.response.user_id.?}); + try stdout.print("\taccount: {s}\n", .{call.response.account.?}); + try stdout.print("\trequestId: {s}\n", .{call.response_metadata.request_id}); +}