Skip to content

Registration crate#2915

Merged
jreidinger merged 21 commits intoapi-v2from
registration_crate
Dec 16, 2025
Merged

Registration crate#2915
jreidinger merged 21 commits intoapi-v2from
registration_crate

Conversation

@jreidinger
Copy link
Copy Markdown
Contributor

@jreidinger jreidinger commented Nov 27, 2025

Problem

With the drop of ruby software service we will also loose suse connect ruby bindings.

Solution

Write crate that acts like suseconnect bindings. We also have to write headers ourself from suseconnect-ng sources. This can be maybe in future send to their git.

Crate implementation is done for now as it export all methods that ruby agama needed, but it can be extended for future if need arise.

Testing

  • Tested manually

To ensure correctness I tested using examples. How to use it:

cd rust/suseconnect-agama
cargo test
../target/debug/examples/announce <regcode>

Feel free to test both correct and invalid SLES16 registration code.

Another example is for listing addons. I hardcoded sles 16 there and it needs to be run on already registered system.

@jreidinger jreidinger marked this pull request as ready for review December 10, 2025 13:24
Copy link
Copy Markdown
Contributor

@imobachgs imobachgs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! Just a few notes, nothing critical.

Thanks!


/// parameters for SUSE Connect calls.
///
/// Based on https://github.com/SUSE/connect-ng/blob/main/internal/connect/config.go#L45
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should use a permalink, because this one might get outdated at some point (yes, I know, permalinks are long and ugly). It would be https://github.com/SUSE/connect-ng/blob/5a200487c50d9c955708b34d0d35ebef47dc5a3e/internal/connect/config.go#L45.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is questionable as on ther hand we are mainly interested in the latest code to see if it changes in a way that can affect us.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's easy to get the latest version just by clicking in the GitHub page or by manually rewriting the commit hash in the URL by "master".

But the opposite way, getting the old original status at the time when wrote the code, is more difficult. So I'd also prefer using permalinks.

Moreover having a git commit allows to easily see a diff from master and check the changes.

type Error = Error;

fn try_from(value: Value) -> Result<Self, Self::Error> {
let Some(credentials) = value.get("credentials").and_then(|c| c.as_array()) else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can do (just a suggestion):

Suggested change
let Some(credentials) = value.get("credentials").and_then(|c| c.as_array()) else {
let Some(credentials) = value.get("credentials").and_then(Value::as_array) else {

You can do the same with others as_* (e.g., as_str).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a bit shorter, so why not.

pub fn announce_system(params: ConnectParams, target_distro: &str) -> Result<Credentials, Error> {
let result_s = unsafe {
let param_json = json!(params).to_string();
let params_c_ptr = CString::new(param_json).unwrap().into_raw();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we document why calling unwrap is OK here? Just forget about it if it is the common approach when writing bindings.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well it is tricky question. Error can happen only if string contain '\0' inside it ( which basically kills C string as C uses \0 for end of string for basic char *). Here when we construct it from json I hope it cannot happen. But maybe we can introduce new error type for malformed strings passed to bindings.

///
/// * `product` - The [Product] to activate.
/// * `params` - Parameters [ConnectParams] for the connection.
/// * `email` - The email address to associate with the activation. Can be empty.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is not the e-mail part of the params struct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is already there...but do not ask me why this call have it as separate param. It is even part of connect config https://github.com/SUSE/connect-ng/blob/main/internal/connect/config.go#L55 .. so my guess is that it is some backward compatibility relict. But checking code it really uses this param and we also use it in ruby part, so for safety I would also use it here.

let params_c_ptr = CString::new(param_json).unwrap().into_raw();

let result_ptr = suseconnect_agama_sys::write_config(params_c_ptr);
let _ = CString::from_raw(params_c_ptr);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are ignoring the result, why is this call needed (just asking)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is done at multiple parts. Basically here the issue is that SUSEConnect headers use "char " and not "const char" like we used in libzypp. Result is that we need to transform CString into_raw and basically give away memory ownership ( for const char* we do not need to do it )....but SUSEConnect won't clear passed string, so we need to take back ownership after the call to ensure that CString will free the memory when it gets out of scope. And that is exactly what happens there.
If you are interested here it is explained https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#method.from_raw

Copy link
Copy Markdown
Contributor

@lslezak lslezak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments.


/// parameters for SUSE Connect calls.
///
/// Based on https://github.com/SUSE/connect-ng/blob/main/internal/connect/config.go#L45
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's easy to get the latest version just by clicking in the GitHub page or by manually rewriting the commit hash in the URL by "master".

But the opposite way, getting the old original status at the time when wrote the code, is more difficult. So I'd also prefer using permalinks.

Moreover having a git commit allows to easily see a diff from master and check the changes.

pub struct ConnectParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
// TODO: maybe use url instead of string?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a I can see it now uses url:Url so the comment can be removed.

let product_spec = ProductSpecification {
identifier: "SLES".to_string(),
version: "16.0".to_string(),
arch: "x86_64".to_string(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is just a testing example, but how difficult would be to detect the real current architecture? We need it in the real code anyway...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, in original code we use rpm arch...sadly using zypper system-architecture returns different string, so it would probably need a bit of processing. I kind of hope that we can get rpm architecture from libzypp. ( which I do not want to use here )

}
}

/// SSL Error codes returned from SUSEConnect.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess a link to the SUSEconnect code would be useful here...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#[derive(Debug, Clone)]
pub struct Service {
/// The name of the service that can be used in libzypp.
pub name: String,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really name or the alias?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably alias, but they call it in suse connect "name". That is always a bit challenge for me in such bindings if I should change names or keep original API names.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see...

SCCApi {
message: String,
// HTTP error code from API
code: u64,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think u32 should be more than enough for HTTP error codes...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, even u16 will be enough, but it is more related to json interger sizes. Maybe even more correct would be i64 as suseconnect also use signed integer https://github.com/SUSE/connect-ng/blob/5a200487c50d9c955708b34d0d35ebef47dc5a3e/pkg/connection/api_error.go#L12

let login = CString::new(login)?.into_raw();
let pwd = CString::new(pwd)?.into_raw();
let path = CString::new(path)?.into_raw();
let empty = CString::new("")?.into_raw();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather use unused_argument name? As more important is "why" and not "what", as is obviously visible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I was a bit scaried to send there anything else, so I replicate explicit empty string as in ruby bindings in connect - https://github.com/SUSE/connect-ng/blob/main/third_party/yast/lib/suse/connect/yast.rb#L169

@jreidinger jreidinger merged commit 709fe02 into api-v2 Dec 16, 2025
11 of 12 checks passed
@jreidinger jreidinger deleted the registration_crate branch December 16, 2025 11:21
imobachgs added a commit that referenced this pull request Jan 10, 2026
Merge the new HTTP API. Each PR has been already reviewed, so it should
be safe to merge it.

* #1829
* #2508
* #2772
* #2826
* #2848
* #2860
* #2863
* #2866
* #2867
* #2869
* #2870
* #2871
* #2872
* #2873
* #2874
* #2875
* #2876
* #2877
* #2880
* #2881
* #2882
* #2884
* #2885
* #2886
* #2891
* #2892
* #2893
* #2894
* #2895
* #2896
* #2897
* #2898
* #2899
* #2900
* #2901
* #2902
* #2903
* #2904
* #2908
* #2909
* #2910
* #2912
* #2913
* #2914
* #2915
* #2916
* #2917
* #2918
* #2920
* #2921
* #2923
* #2924
* #2926
* #2928
* #2929
* #2930
* #2933
* #2934
* #2935
* #2936
* #2938
* #2939
* #2942
* #2943
* #2944
* #2945
* #2946
* #2947
* #2948
* #2950
* #2951
* #2952
* #2954
* #2955
* #2956
* #2957
* #2958
* #2959
* #2960
* #2961
* #2963
* #2964
* #2965
* #2967
* #2968
* #2969
* #2970
* #2971
* #2972
* #2974
* #2975
* #2977
* #2978
* #2980
* #2982
* #2983
* #2984
* #2988
* #2989
* #2991
* #2992
* #2993
* #2994
* #2995
* #2996
* #2997
* #2999
@imobachgs imobachgs mentioned this pull request Mar 17, 2026
imobachgs added a commit that referenced this pull request Mar 17, 2026
Prepare to release version 19.

* #1829
* #2508
* #2772
* #2818
* #2826
* #2848
* #2860
* #2863
* #2864
* #2866
* #2867
* #2869
* #2870
* #2871
* #2872
* #2873
* #2874
* #2875
* #2876
* #2877
* #2880
* #2881
* #2882
* #2884
* #2885
* #2886
* #2891
* #2892
* #2893
* #2894
* #2895
* #2896
* #2897
* #2898
* #2899
* #2900
* #2901
* #2902
* #2903
* #2904
* #2908
* #2909
* #2910
* #2912
* #2913
* #2914
* #2915
* #2916
* #2917
* #2918
* #2920
* #2921
* #2923
* #2924
* #2926
* #2928
* #2929
* #2930
* #2933
* #2934
* #2935
* #2936
* #2937
* #2938
* #2939
* #2942
* #2943
* #2944
* #2945
* #2946
* #2947
* #2948
* #2949
* #2950
* #2951
* #2952
* #2954
* #2955
* #2956
* #2957
* #2958
* #2959
* #2960
* #2961
* #2963
* #2964
* #2965
* #2967
* #2968
* #2969
* #2970
* #2971
* #2972
* #2974
* #2975
* #2977
* #2978
* #2980
* #2981
* #2982
* #2983
* #2984
* #2988
* #2989
* #2990
* #2991
* #2992
* #2993
* #2994
* #2995
* #2996
* #2997
* #2998
* #2999
* #3000
* #3001
* #3002
* #3004
* #3005
* #3006
* #3007
* #3008
* #3009
* #3011
* #3012
* #3013
* #3014
* #3015
* #3016
* #3018
* #3019
* #3020
* #3021
* #3022
* #3023
* #3024
* #3025
* #3026
* #3027
* #3028
* #3029
* #3030
* #3031
* #3033
* #3034
* #3035
* #3036
* #3037
* #3039
* #3040
* #3041
* #3042
* #3043
* #3044
* #3045
* #3046
* #3047
* #3048
* #3049
* #3050
* #3051
* #3052
* #3053
* #3054
* #3055
* #3056
* #3057
* #3058
* #3060
* #3061
* #3062
* #3063
* #3064
* #3065
* #3066
* #3067
* #3068
* #3069
* #3070
* #3071
* #3072
* #3073
* #3074
* #3075
* #3076
* #3077
* #3078
* #3079
* #3086
* #3087
* #3088
* #3089
* #3090
* #3091
* #3092
* #3093
* #3094
* #3095
* #3096
* #3097
* #3098
* #3099
* #3100
* #3101
* #3102
* #3103
* #3104
* #3105
* #3106
* #3107
* #3108
* #3109
* #3110
* #3112
* #3113
* #3114
* #3115
* #3116
* #3117
* #3118
* #3119
* #3120
* #3122
* #3123
* #3124
* #3127
* #3128
* #3129
* #3130
* #3131
* #3133
* #3134
* #3135
* #3136
* #3137
* #3138
* #3139
* #3140
* #3141
* #3142
* #3143
* #3144
* #3145
* #3146
* #3147
* #3148
* #3149
* #3150
* #3151
* #3152
* #3153
* #3154
* #3155
* #3157
* #3158
* #3159
* #3160
* #3161
* #3162
* #3163
* #3164
* #3165
* #3166
* #3167
* #3168
* #3169
* #3170
* #3174
* #3175
* #3176
* #3177
* #3178
* #3179
* #3181
* #3182
* #3184
* #3185
* #3186
* #3188
* #3189
* #3190
* #3191
* #3192
* #3194
* #3195
* #3196
* #3197
* #3198
* #3199
* #3200
* #3201
* #3202
* #3203
* #3205
* #3206
* #3208
* #3209
* #3210
* #3213
* #3214
* #3215
* #3216
* #3217
* #3218
* #3219
* #3220
* #3222
* #3223
* #3224
* #3225
* #3226
* #3227
* #3228
* #3229
* #3230
* #3231
* #3232
* #3233
* #3234
* #3235
* #3236
* #3237
* #3238
* #3239
* #3240
* #3241
* #3242
* #3243
* #3244
* #3246
* #3247
* #3248
* #3250
* #3251
* #3252
* #3253
* #3254
* #3255
* #3256
* #3257
* #3258
* #3259
* #3260
* #3261
* #3262
* #3263
* #3265
* #3266
* #3267
* #3268
* #3269
* #3270
* #3271
* #3272
* #3273
* #3274
* #3275
* #3276
* #3277
* #3278
* #3279
* #3280
* #3281
* #3282
* #3283
* #3284
* #3285
* #3286
* #3287
* #3288
* #3289
* #3290
* #3291
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants