CTY now supports using a custom CSS for the HTML output

CTY now supports using a custom CSS for the HTML output Hey folks. My tool, cty1 now supports adding custom CSS to the HTML output. In an effort to prevent cross-site scripting and other CSS nasties the CSS is pretty limited, sanitized and escaped. Using --css-file now, it’s possible to give it a CSS file that will overwrite everything inside the main HTML file. This allows you to add any customization that you would like to apply to the end result during generation. No more post processing, post editing necessary. ...

August 9, 2025 · 1 min · hannibal

Updated Google OAuth Go Sample - Modern Authentication with Improved UI

Updated Google OAuth Go Sample Hello. I’ve recently updated my Google OAuth Go sample application1 to follow modern standards and practices. The update brings several improvements including a cleaner UI, better error handling, and more robust authentication flows. What’s New New interface for the login side: Nicer errors: Welcome message: Battle arena: And lastly, logout: Technical Updates I added OAuth 2.0 best practices and some proper flows with auth middleware. ...

August 7, 2025 · 1 min · hannibal

External Secrets Operator template rendering tool

External Secrets Operator template rendering tool Once this1 pull request is merged, ESO will be extended with a tool that has the ability to render templates in an object. Let’s step back a little… what are templates even? But… what is ESO even? Okay, so… ESO is external-secrets-operator2. It’s Kubernetes operator than can sync secrets between an external provider, like AWS Parameter/Secret Store, and a cluster. This is bi-directional. Meaning ESO can sync the secret back as well using something called a PushSecret3. The secret will then be pushed to the provider. This way, secrets can be backed up or straight Generated4 to provide ephemeral access to certain resources. ...

January 11, 2025 · 2 min · hannibal

CORScapade; the story why cty doesn't support git flow on web

CORScapade; the story why cty doesn’t support git flow on web Recently, I implemented git based discovery for cty. It means, that the user can provide a git repo URL and cty will clone the content and look for any valid CRDs and discover them. I wanted ot provide this through the front-end as well. However, I ran into some issues… CORS Plain HTTP requests are working fine only if raw.githubusercontent.com is being used. That service doesn’t have CORS. ...

January 7, 2025 · 3 min · hannibal

Using ORAS as a library to interact with OCI repositories

Introducing ORAS into a Library This post talks about using ORAS as a library to interact with OCI repositories. First and foremost I like to keep things simple. I was seeing basic usages around the project I’m working in and some common behaviour that started to emerge. Looking at that behaviour I drawn a preliminary interface. This interface is also something similar that docker remote implementation has in containerd. Looks something like this: ...

January 6, 2025 · 10 min · hannibal

Update your CRDs with confidence

Update your CRDs with confidence Hello. I would like to write about a release for crd-to-sample-yaml1. It’s the release version v0.8.02. This version brings with it a feature to test the validity of your CRD changes. It means that if you change your CRD it will test if the changes do not break working samples of that version. This is achieved by a helm unittest type of YAML based test scenarios and snapshot generation. ...

August 21, 2024 · 2 min · hannibal

Discoverable functional options pattern

Hello. Today’s will be a quick post. Everyone knows and loves/hates functional options1 in Go. The biggest gripe people get with it is, that the options aren’t discoverable and that there is no IDE support for nicely auto-completing options. My thought about this was that, what if we would just hang it on a struct? Let’s see how that looks. Consider this normal server builder with options: type Server struct { Name string Address string Port int } func WithName(name string) ServerOptFn { return func(s *Server) { s.Name = name } } func WithAddress(address string) ServerOptFn { return func(s *Server) { s.Address = address } } func WithPort(port int) ServerOptFn { return func(s *Server) { s.Port = port } } type ServerOptFn func(*Server) func NewServer(opts ...ServerOptFn) *Server { s := &Server{} for _, o := range opts { o(s) } return s } Now, what if you would like to retain the niceness of the clean options pattern where you don’t have to specify and empty struct but still could use a struct to gather the options together? ...

July 1, 2024 · 2 min · hannibal

crd-to-yaml now supports HTML as an output format

Hello! Just wanted to give an update to my crd-to-sample-yaml tool. It, now, supports creating a standalone HTML output. Why, you may ask? Well, now you can host the generated content as a static page on your website. That’s pretty handy. Here is a sample output: Go and get it while it’s hot in version v0.4.0. That’s all. Thanks for reading!

May 9, 2024 · 1 min · hannibal

Generic dig for map key using typed parameters

Generic dig for map key using typed parameters Hello! I was fiddling with a way of getting out values from a map that is of format map[string]any. But I wanted my type safety as well. This was coming from digging out keys from a Metadata field. The metadata was in a JSON format. This is what I came up with: / FetchValueFromMetadata fetches a key from a metadata if it exists. It will recursively look in // embedded values as well. Must be a unique key, otherwise it will just return the first // occurrence. func FetchValueFromMetadata[T any](key string, data *apiextensionsv1.JSON, def T) (t T, _ error) { if data == nil { return def, nil } m := map[string]any{} if err := json.Unmarshal(data.Raw, &m); err != nil { return t, fmt.Errorf("failed to parse JSON raw data: %w", err) } v, err := dig[T](key, m) if err != nil { if errors.Is(err, errKeyNotFound) { return def, nil } } return v, nil } func dig[T any](key string, data map[string]any) (t T, _ error) { if v, ok := data[key]; ok { c, k := v.(T) if !k { return t, fmt.Errorf("failed to convert value to the desired type; was: %T", v) } return c, nil } for _, v := range data { if ty, ok := v.(map[string]any); ok { return dig[T](key, ty) } } return t, errKeyNotFound } The interesting part is the dig method and the type assert to the desired part. Calling this with something like: ...

February 27, 2024 · 2 min · hannibal

CRD to YAML as WASM website

CRD to YAML as WASM website A while ago, I wrote about Generating Sample YAML files from CRDs. It’s a tool I created that lives here. It has a front-end service as well for convenience. I wrote it in a traditional client-server manner. It’s running from a Docker Swarm container. But, as I was thinking about it, nothing in this service requires interaction with a server. It gets some user input, processes it, and has some output. I could have written it in plain Javascript. But, since I don’t know JavaScript, or don’t know it well enough, and I do know GO, and I wanted to become more familiar with WASM, this was the perfect learning opportunity. ...

December 1, 2023 · 5 min · hannibal