Skip to content

Commit aeaa7c5

Browse files
authored
fix: fixes found from actually trying to use this code (#27)
1 parent 4decc7a commit aeaa7c5

28 files changed

+1715
-867
lines changed

pkg/aws/iam.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ func CreateIAMResources(
132132
// - kms:Sign: Allows signing messages using the KMS key
133133
// - kms:GetPublicKey: Allows retrieving the public key associated with the KMS key
134134
func CreateKMSPolicy(key pulumi.StringInput) pulumi.StringOutput {
135-
policy := KMSPolicy{
135+
// Create internal policy with Pulumi types
136+
policy := kmsPolicyInternal{
136137
Version: IAMPolicyVersion,
137-
Statement: []KMSStatement{
138+
Statement: []kmsStatementInternal{
138139
{
139140
Effect: EffectAllow,
140141
Action: []string{
@@ -155,3 +156,64 @@ func CreateKMSPolicy(key pulumi.StringInput) pulumi.StringOutput {
155156
return string(jsonBytes), nil
156157
}).(pulumi.StringOutput)
157158
}
159+
160+
// CreateKMSPolicyFromPublic creates a KMS policy document from public types
161+
// and converts it to internal types for use with Pulumi.
162+
//
163+
// Parameters:
164+
// - policy: The public KMSPolicy struct
165+
//
166+
// Returns:
167+
// - pulumi.StringOutput: A Pulumi output containing the JSON policy document
168+
func CreateKMSPolicyFromPublic(policy KMSPolicy) (pulumi.StringOutput, error) {
169+
if err := policy.Validate(); err != nil {
170+
return pulumi.StringOutput{}, fmt.Errorf("invalid KMS policy: %w", err)
171+
}
172+
173+
// Convert to internal format
174+
internalPolicy := policy.toInternal()
175+
176+
// Convert to JSON string output
177+
// Since we're working with internal types that have Pulumi inputs,
178+
// we need to handle the conversion carefully
179+
statements := internalPolicy.Statement
180+
if len(statements) == 0 {
181+
return pulumi.StringOutput{}, fmt.Errorf("policy must have at least one statement")
182+
}
183+
184+
// For now, we'll create a simple policy with the first statement
185+
// In a more complex scenario, you might need to handle multiple statements differently
186+
firstStmt := statements[0]
187+
188+
return pulumi.All(firstStmt.Resource).ApplyT(func(values []interface{}) (string, error) {
189+
resource := values[0].(string)
190+
// Create a temporary struct for marshaling
191+
tempPolicy := struct {
192+
Version string `json:"Version"`
193+
Statement []struct {
194+
Effect string `json:"Effect"`
195+
Action []string `json:"Action"`
196+
Resource string `json:"Resource"`
197+
} `json:"Statement"`
198+
}{
199+
Version: internalPolicy.Version,
200+
Statement: []struct {
201+
Effect string `json:"Effect"`
202+
Action []string `json:"Action"`
203+
Resource string `json:"Resource"`
204+
}{
205+
{
206+
Effect: firstStmt.Effect,
207+
Action: firstStmt.Action,
208+
Resource: resource,
209+
},
210+
},
211+
}
212+
213+
jsonBytes, err := json.Marshal(tempPolicy)
214+
if err != nil {
215+
return "", err
216+
}
217+
return string(jsonBytes), nil
218+
}).(pulumi.StringOutput), nil
219+
}

pkg/aws/types.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
88
)
99

10+
// Public-facing structs with base Go types
11+
1012
// IAMStatement represents a statement in an IAM policy document.
1113
// It defines a single permission statement that specifies what actions
1214
// are allowed or denied on which resources.
@@ -41,7 +43,7 @@ type KMSStatement struct {
4143
// Action specifies the KMS actions that are allowed or denied
4244
Action []string `json:"Action"`
4345
// Resource specifies the KMS key ARN that the permissions apply to
44-
Resource pulumi.StringInput `json:"Resource"`
46+
Resource string `json:"Resource"`
4547
}
4648

4749
// KMSPolicy represents a complete KMS policy document.
@@ -52,3 +54,39 @@ type KMSPolicy struct {
5254
// Statement contains the list of KMS permission statements
5355
Statement []KMSStatement `json:"Statement"`
5456
}
57+
58+
// Internal structs with Pulumi types
59+
60+
type kmsStatementInternal struct {
61+
Effect string `json:"Effect"`
62+
Action []string `json:"Action"`
63+
Resource pulumi.StringInput `json:"Resource"`
64+
}
65+
66+
type kmsPolicyInternal struct {
67+
Version string `json:"Version"`
68+
Statement []kmsStatementInternal `json:"Statement"`
69+
}
70+
71+
// Conversion functions
72+
73+
// toInternal converts a public KMSStatement to internal format
74+
func (s KMSStatement) toInternal() kmsStatementInternal {
75+
return kmsStatementInternal{
76+
Effect: s.Effect,
77+
Action: s.Action,
78+
Resource: pulumi.String(s.Resource),
79+
}
80+
}
81+
82+
// toInternal converts a public KMSPolicy to internal format
83+
func (p KMSPolicy) toInternal() kmsPolicyInternal {
84+
statements := make([]kmsStatementInternal, len(p.Statement))
85+
for i, stmt := range p.Statement {
86+
statements[i] = stmt.toInternal()
87+
}
88+
return kmsPolicyInternal{
89+
Version: p.Version,
90+
Statement: statements,
91+
}
92+
}

pkg/aws/validation.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package aws
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// Validate validates the IAMStatement
8+
func (s *IAMStatement) Validate() error {
9+
if s.Effect == "" {
10+
return fmt.Errorf("effect is required")
11+
}
12+
if len(s.Action) == 0 {
13+
return fmt.Errorf("action is required")
14+
}
15+
return nil
16+
}
17+
18+
// Validate validates the IAMPolicy
19+
func (p *IAMPolicy) Validate() error {
20+
if p.Version == "" {
21+
return fmt.Errorf("version is required")
22+
}
23+
if len(p.Statement) == 0 {
24+
return fmt.Errorf("statement is required")
25+
}
26+
for i, stmt := range p.Statement {
27+
if err := stmt.Validate(); err != nil {
28+
return fmt.Errorf("statement %d: %w", i, err)
29+
}
30+
}
31+
return nil
32+
}
33+
34+
// Validate validates the KMSStatement
35+
func (s *KMSStatement) Validate() error {
36+
if s.Effect == "" {
37+
return fmt.Errorf("effect is required")
38+
}
39+
if len(s.Action) == 0 {
40+
return fmt.Errorf("action is required")
41+
}
42+
if s.Resource == "" {
43+
return fmt.Errorf("resource is required")
44+
}
45+
return nil
46+
}
47+
48+
// Validate validates the KMSPolicy
49+
func (p *KMSPolicy) Validate() error {
50+
if p.Version == "" {
51+
return fmt.Errorf("version is required")
52+
}
53+
if len(p.Statement) == 0 {
54+
return fmt.Errorf("statement is required")
55+
}
56+
for i, stmt := range p.Statement {
57+
if err := stmt.Validate(); err != nil {
58+
return fmt.Errorf("statement %d: %w", i, err)
59+
}
60+
}
61+
return nil
62+
}

pkg/aws/validation_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package aws
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
// TestIAMStatementValidate tests the validation of IAMStatement
10+
func TestIAMStatementValidate(t *testing.T) {
11+
// Test valid statement
12+
validStmt := IAMStatement{
13+
Effect: "Allow",
14+
Action: []string{"kms:Sign", "kms:GetPublicKey"},
15+
}
16+
err := validStmt.Validate()
17+
assert.NoError(t, err)
18+
19+
// Test missing effect
20+
invalidStmt1 := IAMStatement{
21+
Action: []string{"kms:Sign"},
22+
}
23+
err = invalidStmt1.Validate()
24+
assert.Error(t, err)
25+
assert.Equal(t, "effect is required", err.Error())
26+
27+
// Test missing action
28+
invalidStmt2 := IAMStatement{
29+
Effect: "Allow",
30+
}
31+
err = invalidStmt2.Validate()
32+
assert.Error(t, err)
33+
assert.Equal(t, "action is required", err.Error())
34+
}
35+
36+
// TestIAMPolicyValidate tests the validation of IAMPolicy
37+
func TestIAMPolicyValidate(t *testing.T) {
38+
// Test valid policy
39+
validPolicy := IAMPolicy{
40+
Version: "2012-10-17",
41+
Statement: []IAMStatement{
42+
{
43+
Effect: "Allow",
44+
Action: []string{"kms:Sign"},
45+
},
46+
},
47+
}
48+
err := validPolicy.Validate()
49+
assert.NoError(t, err)
50+
51+
// Test missing version
52+
invalidPolicy1 := IAMPolicy{
53+
Statement: []IAMStatement{
54+
{
55+
Effect: "Allow",
56+
Action: []string{"kms:Sign"},
57+
},
58+
},
59+
}
60+
err = invalidPolicy1.Validate()
61+
assert.Error(t, err)
62+
assert.Equal(t, "version is required", err.Error())
63+
64+
// Test missing statement
65+
invalidPolicy2 := IAMPolicy{
66+
Version: "2012-10-17",
67+
}
68+
err = invalidPolicy2.Validate()
69+
assert.Error(t, err)
70+
assert.Equal(t, "statement is required", err.Error())
71+
}
72+
73+
// TestKMSStatementValidate tests the validation of KMSStatement
74+
func TestKMSStatementValidate(t *testing.T) {
75+
// Test valid statement
76+
validStmt := KMSStatement{
77+
Effect: "Allow",
78+
Action: []string{"kms:Sign", "kms:GetPublicKey"},
79+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
80+
}
81+
err := validStmt.Validate()
82+
assert.NoError(t, err)
83+
84+
// Test missing effect
85+
invalidStmt1 := KMSStatement{
86+
Action: []string{"kms:Sign"},
87+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
88+
}
89+
err = invalidStmt1.Validate()
90+
assert.Error(t, err)
91+
assert.Equal(t, "effect is required", err.Error())
92+
93+
// Test missing action
94+
invalidStmt2 := KMSStatement{
95+
Effect: "Allow",
96+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
97+
}
98+
err = invalidStmt2.Validate()
99+
assert.Error(t, err)
100+
assert.Equal(t, "action is required", err.Error())
101+
102+
// Test missing resource
103+
invalidStmt3 := KMSStatement{
104+
Effect: "Allow",
105+
Action: []string{"kms:Sign"},
106+
}
107+
err = invalidStmt3.Validate()
108+
assert.Error(t, err)
109+
assert.Equal(t, "resource is required", err.Error())
110+
}
111+
112+
// TestKMSPolicyValidate tests the validation of KMSPolicy
113+
func TestKMSPolicyValidate(t *testing.T) {
114+
// Test valid policy
115+
validPolicy := KMSPolicy{
116+
Version: "2012-10-17",
117+
Statement: []KMSStatement{
118+
{
119+
Effect: "Allow",
120+
Action: []string{"kms:Sign", "kms:GetPublicKey"},
121+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
122+
},
123+
},
124+
}
125+
err := validPolicy.Validate()
126+
assert.NoError(t, err)
127+
128+
// Test missing version
129+
invalidPolicy1 := KMSPolicy{
130+
Statement: []KMSStatement{
131+
{
132+
Effect: "Allow",
133+
Action: []string{"kms:Sign"},
134+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
135+
},
136+
},
137+
}
138+
err = invalidPolicy1.Validate()
139+
assert.Error(t, err)
140+
assert.Equal(t, "version is required", err.Error())
141+
142+
// Test missing statement
143+
invalidPolicy2 := KMSPolicy{
144+
Version: "2012-10-17",
145+
}
146+
err = invalidPolicy2.Validate()
147+
assert.Error(t, err)
148+
assert.Equal(t, "statement is required", err.Error())
149+
}
150+
151+
// TestKMSPolicyToInternal tests the conversion from public to internal types
152+
func TestKMSPolicyToInternal(t *testing.T) {
153+
// Create a public policy
154+
publicPolicy := KMSPolicy{
155+
Version: "2012-10-17",
156+
Statement: []KMSStatement{
157+
{
158+
Effect: "Allow",
159+
Action: []string{"kms:Sign", "kms:GetPublicKey"},
160+
Resource: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab",
161+
},
162+
},
163+
}
164+
165+
// Convert to internal
166+
internalPolicy := publicPolicy.toInternal()
167+
168+
// Verify the conversion
169+
assert.Equal(t, publicPolicy.Version, internalPolicy.Version)
170+
assert.Len(t, internalPolicy.Statement, 1)
171+
assert.Equal(t, publicPolicy.Statement[0].Effect, internalPolicy.Statement[0].Effect)
172+
assert.Equal(t, publicPolicy.Statement[0].Action, internalPolicy.Statement[0].Action)
173+
assert.NotNil(t, internalPolicy.Statement[0].Resource)
174+
}

0 commit comments

Comments
 (0)